一个支持间隔,多色,圆角,水平,竖直的进度条
特点
- 支持水平和竖直方向
- 支持进度条间隔颜色
- 支持多色设置
- 支持起始圆角
使用方式
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())
)
属性
属性 | 类型 | 说明 |
---|---|---|
direction | enum |
进度条的方向,水平或竖直 |
max | int |
进度块的个数 |
progress | int |
高亮进度块的个数 |
intervalSize | int |
进度块之间间隔的大小。当水平时,代表宽度;当竖直时,代表高度 |
size | Size |
控件的尺寸 |
highlightColor | Color |
高亮进度块的颜色 |
defaultColor | Color |
进度块的默认颜色 |
intervalColor | Color |
间隔块的默认颜色 |
intervalHighlightColor | Color |
高亮进度块之间的间隔块的颜色 |
reverse | bool |
是否逆序填充 |
radius | int |
起始块的圆角 |
⌨ → https://github.com/stefanJi/IntervalProgressBar
实现
抽象基类
- 负责计算一些水平和竖直进度条的公有属性
- 调用子类的
paintBlock
执行具体的draw
操作
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;
final Paint _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++) {
/// 调用子类执行绘制
paintBlock(canvas, i, blockSize);
}
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
final old = oldDelegate as IntervalProgressPainter;
return old.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(int index) =>
index != max - 1 &&
(intervalColor != IntervalProgressBar.TRANSPARENT ||
intervalHighlightColor != IntervalProgressBar.TRANSPARENT);
}
水平进度条
- 计算每个进度块的尺寸
@override
Size calBlockSize() =>
Size(((bound.width - intervalSize * (max - 1)) / max), bound.height);
- 绘制每个块
@override
void paintBlock(Canvas canvas, int i, Size blockSize) {
/// blockSize: calBlockSize 的返回值
/// i: 块的索引
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();
/// 画布移动 dx: 进度块宽度+间隔块宽度
canvas.translate(dx, 0);
/// 绘制起始圆角
if (shouldDrawStartRadius(i)) {
rect = _drawLeftRound(canvas, rect);
}
/// 绘制末尾圆角
if (shouldDrawEndRadius(i)) {
rect = _drawRightRound(canvas, rect);
}
/// 绘制块
canvas.drawRect(rect, _paint);
/// 绘制间隔块
if (shouldDrawInterval(i)) {
_paint.color =
highlightInterval(i) ? intervalHighlightColor : intervalColor;
canvas.drawRect(
Rect.fromLTRB(
blockWidth,
0,
blockWidth + intervalSize,
bound.height,
),
_paint);
}
canvas.restore();
}
- 绘制一边带圆角,另一半不带圆角的矩形
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();
}
}