Flutter中实现空心圆环有多种方法,以下列举两种常用的实现方法:
- 使用CustomPaint自定义绘制
class CircleProgressBar extends StatelessWidget {
final double strokeWidth; // 圆环宽度
final double value; // 进度值
final Color backgroundColor; // 圆环背景色
final Color foregroundColor; // 进度圆环颜色
CircleProgressBar({
this.strokeWidth = 10,
this.value = 0,
this.backgroundColor = Colors.grey,
this.foregroundColor = Colors.blue,
}) : assert(strokeWidth != null),
assert(value != null && value >= 0 && value <= 1),
assert(backgroundColor != null),
assert(foregroundColor != null);
@override
Widget build(BuildContext context) {
return CustomPaint(
painter: CircleProgressBarPainter(
strokeWidth: strokeWidth,
value: value,
backgroundColor: backgroundColor,
foregroundColor: foregroundColor,
),
);
}
}
class CircleProgressBarPainter extends CustomPainter {
final double strokeWidth;
final double value;
final Color backgroundColor;
final Color foregroundColor;
CircleProgressBarPainter({
this.strokeWidth = 10,
this.value = 0,
this.backgroundColor = Colors.grey,
this.foregroundColor = Colors.blue,
});
@override
void paint(Canvas canvas, Size size) {
final Paint bgPaint = Paint()
..color = backgroundColor
..strokeWidth = strokeWidth
..style = PaintingStyle.stroke;
final Paint fgPaint = Paint()
..color = foregroundColor
..strokeWidth = strokeWidth
..style = PaintingStyle.stroke
..strokeCap = StrokeCap.round;
final center = Offset(size.width / 2, size.height / 2);
final radius = (size.width - strokeWidth) / 2;
canvas.drawCircle(center, radius, bgPaint);
// value为0时不绘制进度圆环
if (value > 0) {
canvas.drawArc(
Rect.fromCircle(center: center, radius: radius),
-math.pi / 2,
math.pi * 2 * value,
false,
fgPaint,
);
}
}
@override
bool shouldRepaint(CircleProgressBarPainter oldDelegate) =>
value != oldDelegate.value ||
backgroundColor != oldDelegate.backgroundColor ||
foregroundColor != oldDelegate.foregroundColor;
}
- 使用插件flutter_svg实现
import 'package:flutter_svg/flutter_svg.dart';
class CircleProgressBar extends StatelessWidget {
final double strokeWidth; // 圆环宽度
final double value; // 进度值
final Color backgroundColor; // 圆环背景色
final Color foregroundColor; // 进度圆环颜色
CircleProgressBar({
this.strokeWidth = 10,
this.value = 0,
this.backgroundColor = Colors.grey,
this.foregroundColor = Colors.blue,
}) : assert(strokeWidth != null),
assert(value != null && value >= 0 && value <= 1),
assert(backgroundColor != null),
assert(foregroundColor != null);
@override
Widget build(BuildContext context) {
return Center(
child: SvgPicture.asset(
'assets/circle_progress_bar.svg',
color: foregroundColor,
semanticsLabel: 'CircleProgressBar',
fit: BoxFit.cover,
width: double.infinity,
height: double.infinity,
matchTextDirection: true,
// 设置操作只为旋转
allowDrawingOutsideViewBox: false,
alignment: Alignment.center,
// transform为SVG文件中的transform
// 根据value计算出需要旋转的角度
// 需要在SVG文件中加入transform='rotate(-90)',保证起始位置为12点钟方向
// 如下所示:
// <g transform='rotate(-90)'>
// <circle cx='50%' cy='50%' r='50%' />
// <path id='arc' d='M50 0 A50 50 0 ...' />
// </g>
// 其中-transform.value为不包含value之前的角度
transform: Matrix4.rotationZ(-math.pi / 2 - math.pi * 2 * value),
),
);
}
}