A support interval, multicolor, rounded corner, horizontal, vertical progress bar

The characteristics of

  • Supports horizontal and vertical directions
  • Supports progress bar interval colors
  • Support multicolor Settings
  • Initial rounded corners are supported

use

Center(
   child: Row(
       mainAxisAlignment: MainAxisAlignment.center,
       children: [10.29.18.27.16.15.24.3.20.10].map<Widget>((i) {
         return Padding(
             padding: EdgeInsets.only(right: 10),
             child: IntervalProgressBar(
                 direction: IntervalProgressDirection.vertical,
                 max: 30,
                 progress: i,
                 intervalSize: 2,
                 size: Size(12.200),
                 highlightColor: Colors.red,
                 defaultColor: Colors.grey,
                 intervalColor: Colors.transparent,
                 intervalHighlightColor: Colors.transparent,
                 reverse: true,
                 radius: 0));
       }).toList())
)
Copy the code

attribute

attribute type instructions
direction enum The direction of the progress bar, horizontal or vertical
max int Number of progress blocks
progress int Highlight the number of progress blocks
intervalSize int The size of the interval between progress blocks. When horizontal, it represents width; When vertical, it means height
size Size Control size
highlightColor Color Highlight the color of the progress block
defaultColor Color The default color of the progress block
intervalColor Color The default color of the interval block
intervalHighlightColor Color Highlight the color of the spacing blocks between progress blocks
reverse bool Whether to fill it in reverse order
radius int Rounded corner of starting block

implementation

Abstract base class

  • Calculates public properties for horizontal and vertical progress bars
  • Of calling a subclasspaintBlockExecute specificdrawoperation
abstract class IntervalProgressPainter extends CustomPainter {
  final int max;
  final int progress;
  final int intervalSize;
  final Color highlightColor;
  final Color defaultColor;
  final Color intervalColor;
  final Color intervalHighlightColor;
  final double radius;
  final bool reverse;

  finalPaint _paint = Paint() .. style = PaintingStyle.fill .. isAntiAlias =true;

  Rect bound;

  IntervalProgressPainter(
      this.max,
      this.progress,
      this.intervalSize,
      this.highlightColor,
      this.defaultColor,
      this.intervalColor,
      this.intervalHighlightColor,
      this.radius,
      this.reverse);

  @override
  @mustCallSuper
  void paint(Canvas canvas, Size size) {
    if (progress > max) {
      throw Exception("progress must <= max");
    }
    bound = Offset.zero & size;
    Size blockSize = calBlockSize();
    for (int i = 0; i < max; i++) {
      /// Call the subclass to perform the drawingpaintBlock(canvas, i, blockSize); }}@override
  bool shouldRepaint(CustomPainter oldDelegate) {
    final old = oldDelegate as IntervalProgressPainter;
    returnold.max ! = max || old.progress ! = progress || old.intervalSize ! = intervalSize || old.intervalColor ! = intervalColor || old.defaultColor ! = defaultColor || old.highlightColor ! = highlightColor || old.intervalHighlightColor ! = intervalHighlightColor || old.radius ! = radius; }bool highlightBlock(int index) =>
      reverse ? index >= (max - progress) : index < progress;

  bool highlightInterval(int index) =>
      reverse ? index >= (max - progress - 1) : index < progress - 1;

  void paintBlock(Canvas canvas, int blockIndex, Size blockSize);

  Size calBlockSize();

  bool shouldDrawStartRadius(int index) => index == 0 && radius > 0;

  bool shouldDrawEndRadius(int index) => index == max - 1 && radius > 0;

  bool shouldDrawInterval(intindex) => index ! = max -1&& (intervalColor ! = IntervalProgressBar.TRANSPARENT || intervalHighlightColor ! = IntervalProgressBar.TRANSPARENT); }Copy the code

Horizontal progress bar

  • Calculate the size of each progress block
  @override
  Size calBlockSize() =>
      Size(((bound.width - intervalSize * (max - 1)) / max), bound.height);
Copy the code
  • Draw each block
  @override
  void paintBlock(Canvas canvas, int i, Size blockSize) {
    /// blockSize: return value of calBlockSize
    /// I: block index

    final blockWidth = blockSize.width;
    final highlight = highlightBlock(i);
    final dx = (blockWidth + intervalSize) * i;

    Rect rect = Rect.fromLTRB(0.0, blockWidth, bound.height);
    _paint.color = highlight ? highlightColor : defaultColor;
    canvas.save();
    /// Canvas moves dx: progress block width + interval block width
    canvas.translate(dx, 0);
    /// Draw the initial rounded corner
    if (shouldDrawStartRadius(i)) {
      rect = _drawLeftRound(canvas, rect);
    }
    
    /// Draw the rounded corners at the end
    if (shouldDrawEndRadius(i)) {
      rect = _drawRightRound(canvas, rect);
    }
    / / / drawing block
    canvas.drawRect(rect, _paint);

    /// Draw spacer blocks
    if (shouldDrawInterval(i)) {
      _paint.color =
          highlightInterval(i) ? intervalHighlightColor : intervalColor;
      canvas.drawRect(
          Rect.fromLTRB(
            blockWidth,
            0,
            blockWidth + intervalSize,
            bound.height,
          ),
          _paint);
    }
    canvas.restore();
  }
Copy the code
  • Draws a rectangle with rounded corners on one side and unrounded corners on the other
  void _drawRadius(Canvas canvas, Rect rect, Rect clipRect) {
    final roundRect = RRect.fromLTRBR(
        rect.left, rect.top, rect.right, rect.bottom, Radius.circular(radius));
    final path = Path()..addRRect(roundRect);
    canvas.save();
    canvas.clipRect(clipRect, clipOp: ClipOp.difference);
    canvas.drawPath(path, _paint);
    canvas.restore();
  }
}
Copy the code

The vertical progress bar is similar, please see the source code

Github.com/stefanJi/In…