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

Flutter中如何高效生成可自定义分段颜色的自定义形状?

Flutter 高效创建可自定义分段颜色的自定义形状

当然有,Flutter里用CustomPainter就能高效实现这类需求,它是自定义绘制的核心组件,灵活度高且性能可控。下面是具体实现步骤:

1. 定义分段数据模型

先创建一个类来存储每个分段的颜色和对应的尺寸(比如角度、长度,根据你的形状调整):

class Segment {
  final Color color;
  final double angle; // 示例用角度(弧度),如果是线性分段可换成长度

  Segment({required this.color, required this.angle});
}

2. 实现自定义绘制器

以环形分段为例(匹配你提供的参考图样式),实现CustomPainter子类来绘制每个分段:

import 'dart:math' as math;
import 'package:flutter/material.dart';

class CustomSegmentPainter extends CustomPainter {
  final List<Segment> segments;
  final double strokeWidth;
  final double radius;

  CustomSegmentPainter({
    required this.segments,
    this.strokeWidth = 20.0,
    this.radius = 100.0,
  });

  @override
  void paint(Canvas canvas, Size size) {
    final center = Offset(size.width / 2, size.height / 2);
    double currentAngle = -math.pi / 2; // 从顶部开始绘制

    for (final segment in segments) {
      final paint = Paint()
        ..color = segment.color
        ..style = PaintingStyle.stroke
        ..strokeWidth = strokeWidth
        ..strokeCap = StrokeCap.round; // 可选:给分段端点加圆角

      // 绘制环形分段
      canvas.drawArc(
        Rect.fromCircle(center: center, radius: radius),
        currentAngle,
        segment.angle,
        false,
        paint,
      );

      currentAngle += segment.angle;
    }
  }

  @override
  bool shouldRepaint(covariant CustomSegmentPainter oldDelegate) {
    // 仅当数据变化时重绘,优化性能
    return oldDelegate.segments != segments ||
        oldDelegate.strokeWidth != strokeWidth ||
        oldDelegate.radius != radius;
  }
}

如果你的形状是其他类型(比如多边形分段、线性分段),只需要修改paint方法里的绘制逻辑:用Path构建每个分段的轮廓,再调用canvas.drawPath绘制即可。

3. 在Widget中使用

把自定义绘制器放到CustomPaint组件中,就能在界面上显示:

class CustomSegmentWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 定义分段数据,可根据需求动态修改
    final segments = [
      Segment(color: Colors.red, angle: math.pi / 4),
      Segment(color: Colors.blue, angle: math.pi / 2),
      Segment(color: Colors.green, angle: math.pi / 3),
      Segment(color: Colors.yellow, angle: 5 * math.pi / 12),
    ];

    return CustomPaint(
      size: const Size(250, 250), // 设置绘制区域大小
      painter: CustomSegmentPainter(segments: segments),
    );
  }
}

动态修改分段颜色

如果需要实时修改分段颜色,把segments放到StatefulWidget的状态中,通过setState更新数据即可:

class DynamicSegmentWidget extends StatefulWidget {
  @override
  State<DynamicSegmentWidget> createState() => _DynamicSegmentWidgetState();
}

class _DynamicSegmentWidgetState extends State<DynamicSegmentWidget> {
  late List<Segment> segments;

  @override
  void initState() {
    super.initState();
    segments = [
      Segment(color: Colors.red, angle: math.pi / 4),
      Segment(color: Colors.blue, angle: math.pi / 2),
    ];
  }

  void changeFirstSegmentColor() {
    setState(() {
      segments[0] = Segment(color: Colors.purple, angle: segments[0].angle);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        CustomPaint(
          size: const Size(250, 250),
          painter: CustomSegmentPainter(segments: segments),
        ),
        ElevatedButton(
          onPressed: changeFirstSegmentColor,
          child: const Text("修改第一个分段颜色"),
        ),
      ],
    );
  }
}

性能优化提示

  • shouldRepaint方法只在数据或配置变化时返回true,避免无意义的重绘;
  • 如果分段数量和形状固定,可考虑用RepaintBoundary包裹,隔离绘制区域,减少重绘范围;
  • 复杂形状可提前计算路径缓存,避免每次绘制都重新计算。

内容的提问来源于stack exchange,提问作者Parama Artha

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 03:01:11