Flutter中如何用Custom Painter绘制非堆叠饼图并添加百分比标签
解决Flutter CustomPainter饼图弧堆叠及百分比显示问题
问题分析
原代码中所有弧的起始角度固定为 -math.pi/2,导致所有弧从同一位置开始绘制,出现堆叠覆盖的情况;同时缺少文本绘制逻辑,无法显示各部分百分比。
修复方案
- 累计起始角度:维护变量记录当前弧的起始角度,每次绘制完一个弧后,将起始角度累加当前弧的角度,实现弧的依次衔接。
- 绘制百分比文本:计算每个弧的中间角度,结合饼图中心和半径算出文本位置,使用
TextPainter绘制百分比文本。
修改后的完整代码
import 'dart:math' as math; import 'package:flutter/material.dart'; class PieChart extends CustomPainter { final List<int> percent = [50, 20, 30]; @override void paint(Canvas canvas, Size size) { final Paint paint = Paint()..style = PaintingStyle.fill; final double radius = math.min(size.width / 2, size.height / 2); final Offset center = Offset(size.width / 2, size.height / 2); // 累计起始角度,初始从顶部(-π/2)开始 double startAngle = -math.pi / 2; for (int i = 0; i < percent.length; i++) { final double arcAngle = 2 * math.pi * (percent[i] / 100); // 生成随机颜色 paint.color = Color((math.Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0); // 绘制衔接的弧 canvas.drawArc( Rect.fromCircle(center: center, radius: radius), startAngle, arcAngle, true, paint, ); // 绘制百分比文本 _drawPercentageText(canvas, center, radius, startAngle, arcAngle, percent[i]); // 更新起始角度,为下一个弧做准备 startAngle += arcAngle; } } void _drawPercentageText(Canvas canvas, Offset center, double radius, double startAngle, double arcAngle, int percentage) { // 计算弧的中间角度 final double middleAngle = startAngle + arcAngle / 2; // 文本向内偏移,避免超出饼图 final double textRadius = radius * 0.7; final Offset textOffset = Offset( center.dx + math.cos(middleAngle) * textRadius, center.dy + math.sin(middleAngle) * textRadius, ); final TextPainter textPainter = TextPainter( text: TextSpan( text: '$percentage%', style: const TextStyle( color: Colors.white, fontSize: 16, fontWeight: FontWeight.bold, ), ), textDirection: TextDirection.ltr, ); textPainter.layout(); // 将文本居中绘制在目标位置 textPainter.paint( canvas, Offset( textOffset.dx - textPainter.width / 2, textOffset.dy - textPainter.height / 2, ), ); } @override bool shouldRepaint(PieChart oldDelegate) => false; @override bool shouldRebuildSemantics(PieChart oldDelegate) => false; }
关键代码说明
- 弧衔接逻辑:
startAngle变量初始指向饼图顶部,每次绘制完弧后累加当前弧的角度,确保下一个弧从当前弧的结束位置开始绘制。 - 文本绘制逻辑:通过三角函数计算弧的中间位置坐标,使用
TextPainter实现文本居中显示,同时设置向内偏移的半径,让文本显示在饼图内部。
内容的提问来源于stack exchange,提问作者Naduel
相关产品推荐
相关产品推荐

