You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter实现圆形内多段自定义起始角度圆弧(12小时时间范围)

自定义绘制实现多段独立起始角度的时钟式圆弧

现成的图表包无法满足单段圆弧自定义起始角度的需求,直接用CustomPainter手动绘制是最灵活的解决方案,以下是完整实现:

实现思路

  1. 定义数据结构存储每段圆弧的配置(起始时间/角度、时长/跨度、颜色)
  2. 通过CustomPainter绘制时钟外框、刻度,以及每段自定义圆弧
  3. 处理角度转换: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 19:07:45