Flutter for OpenHarmony:从零搭建幸运大转盘app(二)转盘绑制
转盘的绘制是通过实现的。在中定义@overridecenter— 转盘中心点radius— 转盘半径sweepAngle— 每个扇形的圆心角(360度 ÷ 奖品数量)

上一篇搭好了项目框架,这一篇开始实现核心功能——转盘的绘制。转盘是整个应用的视觉中心,需要用到Flutter的自定义绘制能力。
理解转盘结构
转盘由几部分组成:
- 扇形区域 — 每个奖品占一个扇形,用不同颜色区分
- 分隔线 — 白色线条分隔各个扇形
- 文字标签 — 奖品名称,沿着扇形弧线排列
- 外圈边框 — 白色边框,增强视觉效果
创建奖品数据模型
首先定义奖品的数据结构。创建lib/models/prize.dart:
class Prize {
final String id;
final String name;
final Color color;
final IconData icon;
Prize({
required this.id,
required this.name,
required this.color,
required this.icon,
});
}
这里定义了奖品的基本属性:id 用于唯一标识,name 是奖品名称,color 是转盘上的颜色,icon 是显示的图标。
自定义绘制转盘
转盘的绘制是通过CustomPainter实现的。在lib/pages/wheel_page.dart中定义WheelPainter类:
class WheelPainter extends CustomPainter {
final List<Prize> prizes;
WheelPainter({required this.prizes});
void paint(Canvas canvas, Size size) {
final center = Offset(size.width / 2, size.height / 2);
final radius = size.width / 2;
final sweepAngle = 2 * pi / prizes.length;
这里计算了几个关键参数:
- center — 转盘中心点
- radius — 转盘半径
- sweepAngle — 每个扇形的圆心角(360度 ÷ 奖品数量)
绘制扇形
接下来遍历每个奖品,绘制对应的扇形:
for (int i = 0; i < prizes.length; i++) {
final paint = Paint()..color = prizes[i].color;
final startAngle = i * sweepAngle - pi / 2;
canvas.drawArc(
Rect.fromCircle(center: center, radius: radius),
startAngle,
sweepAngle,
true,
paint,
);
这里用drawArc方法绘制扇形。startAngle 减去 pi/2 是为了让第一个扇形从顶部开始。true 参数表示填充扇形。
绘制分隔线
在每个扇形的起始位置绘制一条白色分隔线:
canvas.drawLine(
center,
Offset(
center.dx + radius * cos(startAngle),
center.dy + radius * sin(startAngle),
),
Paint()
..color = Colors.white
..strokeWidth = 2,
);
分隔线从中心点出发,指向扇形的边界。用三角函数计算端点坐标。
绘制文字标签
奖品名称需要沿着扇形弧线排列,这需要一些几何计算:
final textAngle = startAngle + sweepAngle / 2;
final textRadius = radius * 0.65;
final textCenter = Offset(
center.dx + textRadius * cos(textAngle),
center.dy + textRadius * sin(textAngle),
);
final textPainter = TextPainter(
text: TextSpan(
text: prizes[i].name,
style: const TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
textDirection: TextDirection.ltr,
)..layout();
textAngle 是扇形的中心角,文字放在这个位置。textRadius 设为半径的65%,这样文字不会太靠近边缘。
旋转文字方向
文字需要沿着扇形方向旋转,这样看起来更自然:
canvas.save();
canvas.translate(textCenter.dx, textCenter.dy);
canvas.rotate(textAngle + pi / 2);
textPainter.paint(
canvas,
Offset(-textPainter.width / 2, -textPainter.height / 2),
);
canvas.restore();
先用save()保存画布状态,然后平移到文字位置,旋转画布,绘制文字,最后用restore()恢复画布状态。这样做是为了避免旋转影响其他绘制操作。
绘制外圈边框
最后加上一个白色的外圈边框,增强视觉效果:
canvas.drawCircle(
center,
radius,
Paint()
..color = Colors.white
..style = PaintingStyle.stroke
..strokeWidth = 4,
);
}
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}
shouldRepaint 返回 false 表示转盘内容不会变化,不需要重新绘制。
在页面中使用转盘
在WheelPage的build方法中,用CustomPaint显示转盘:
CustomPaint(
size: const Size(300, 300),
painter: WheelPainter(prizes: _prizeManager.prizes),
)
这里把转盘大小设为300x300,传入奖品列表给WheelPainter。
测试转盘
现在可以运行应用看看转盘效果了。如果一切正常,你应该能看到一个彩色的转盘,上面有六个扇形,分别代表不同的奖品。
如果文字显示不全或位置不对,可以调整textRadius的值。比如改成radius * 0.6或radius * 0.7试试。
常见问题
文字重叠或显示不全
这通常是因为奖品名称太长。可以在TextPainter的maxLines参数设为1,然后用overflow: TextOverflow.ellipsis截断过长的文字。
扇形颜色不对
检查一下PrizeManager中定义的奖品颜色是否正确。如果想改颜色,直接修改Prize对象的color属性就行。
转盘显示不完整
确保CustomPaint的size足够大,至少要300x300。如果容器太小,转盘会被裁剪。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐



所有评论(0)