Flutter实现圆形内多段自定义起始角度圆弧(12小时时间范围)
自定义绘制实现多段独立起始角度的时钟式圆弧
现成的图表包无法满足单段圆弧自定义起始角度的需求,直接用CustomPainter手动绘制是最灵活的解决方案,以下是完整实现:
实现思路
- 定义数据结构存储每段圆弧的配置(起始时间/角度、时长/跨度、颜色)
- 通过
CustomPainter绘制时钟外框、刻度,以及每段自定义圆弧 - 处理角度转换:Flutter Canvas默认0°指向右侧,需偏移-90°让12点朝上,1小时对应30°(360°/12)
完整代码示例
首先定义存储圆弧信息的数据类:
class TimeArc { // 起始小时(1-12),也可直接传入弧度制起始角度 final int startHour; // 持续小时数 final double durationHours; // 圆弧颜色 final Color color; TimeArc({ required this.startHour, required this.durationHours, required this.color, }); }
实现自定义Painter:
class ClockArcPainter extends CustomPainter { final List<TimeArc> timeArcs; final double strokeWidth; ClockArcPainter({ required this.timeArcs, this.strokeWidth = 16.0, }); @override void paint(Canvas canvas, Size size) { final center = Offset(size.width / 2, size.height / 2); final radius = min(size.width, size.height) / 2 - strokeWidth / 2; // 绘制时钟外框 final outerCirclePaint = Paint() ..color = Colors.grey.shade300 ..style = PaintingStyle.stroke ..strokeWidth = 2.0; canvas.drawCircle(center, radius, outerCirclePaint); // 绘制时钟刻度 final tickPaint = Paint()..color = Colors.black; for (int i = 0; i < 12; i++) { final tickLength = i % 3 == 0 ? 12.0 : 6.0; final angle = (i * 30) * pi / 180 - pi / 2; // 转弧度并偏移-90°,让12点朝上 final start = Offset( center.dx + radius * cos(angle), center.dy + radius * sin(angle), ); final end = Offset( center.dx + (radius - tickLength) * cos(angle), center.dy + (radius - tickLength) * sin(angle), ); canvas.drawLine(start, end, tickPaint); } // 绘制每段自定义圆弧 final arcPaint = Paint() ..style = PaintingStyle.stroke ..strokeWidth = strokeWidth ..strokeCap = StrokeCap.round; // 圆弧两端圆角,匹配示例效果 for (final arc in timeArcs) { // 计算起始角度(弧度) final startAngle = (arc.startHour * 30) * pi / 180 - pi / 2; // 计算扫过的角度(弧度) final sweepAngle = arc.durationHours * 30 * pi / 180; arcPaint.color = arc.color; canvas.drawArc( Rect.fromCircle(center: center, radius: radius), startAngle, sweepAngle, false, // 描边模式设为false arcPaint, ); } } @override bool shouldRepaint(covariant ClockArcPainter oldDelegate) { return oldDelegate.timeArcs != timeArcs || oldDelegate.strokeWidth != strokeWidth; } }
在页面中使用该自定义Widget:
class ClockArcScreen extends StatelessWidget { @override Widget build(BuildContext context) { final timeArcs = [ TimeArc(startHour: 2, durationHours: 2.5, color: Colors.blue), TimeArc(startHour: 5, durationHours: 1.5, color: Colors.green), TimeArc(startHour: 9, durationHours: 3, color: Colors.orange), ]; return Scaffold( appBar: AppBar(title: Text('时钟式时间圆弧')), body: Center( child: CustomPaint( size: Size(300, 300), painter: ClockArcPainter(timeArcs: timeArcs), ), ), ); } }
关键说明
- 若不需要基于小时计算,可直接在
TimeArc中传入弧度制的起始角度和扫过角度,跳过小时转角度的步骤 - 可根据需求调整外框颜色、刻度样式、圆弧宽度等参数
strokeCap设为StrokeCap.round可让圆弧两端更圆润,贴合示例图效果
内容的提问来源于stack exchange,提问作者milano zz
相关产品推荐
相关产品推荐

