如何在Flutter中实现按钮样式的环形饼图?
Flutter 实现按钮式环形饼图
如果现成的饼图包满足不了需求,用CustomPainter自定义绘制是最灵活的方案,以下是适配你需求的实现代码:
自定义环形饼图绘制类
import 'package:flutter/material.dart'; class RingButtonPainter extends CustomPainter { final double progress; // 进度值(0-1) final Color ringColor; // 环形底色 final Color progressColor; // 进度环颜色 final bool isSelected; // 是否选中状态 RingButtonPainter({ required this.progress, required this.ringColor, required this.progressColor, required this.isSelected, }); @override void paint(Canvas canvas, Size size) { final center = Offset(size.width / 2, size.height / 2); final radius = size.width / 2; final strokeWidth = 8.0; // 绘制底层环形背景 final backgroundPaint = Paint() ..color = ringColor ..style = PaintingStyle.stroke ..strokeWidth = strokeWidth ..strokeCap = StrokeCap.round; canvas.drawCircle(center, radius - strokeWidth / 2, backgroundPaint); // 绘制进度环(选中状态才显示) if (isSelected) { final progressPaint = Paint() ..color = progressColor ..style = PaintingStyle.stroke ..strokeWidth = strokeWidth ..strokeCap = StrokeCap.round; canvas.drawArc( Rect.fromCircle(center: center, radius: radius - strokeWidth / 2), -0.5 * 3.1416, // 从顶部开始绘制 progress * 2 * 3.1416, // 进度对应的弧度 false, progressPaint, ); } } @override bool shouldRepaint(covariant RingButtonPainter oldDelegate) { return oldDelegate.progress != progress || oldDelegate.isSelected != isSelected || oldDelegate.ringColor != ringColor || oldDelegate.progressColor != progressColor; } }
封装成可交互的按钮组件
class RingButton extends StatefulWidget { final IconData icon; final double initialProgress; final Color ringColor; final Color progressColor; final Color iconColor; final VoidCallback? onTap; const RingButton({ super.key, required this.icon, this.initialProgress = 0.0, this.ringColor = Colors.grey.shade300, this.progressColor = Colors.blue, this.iconColor = Colors.black, this.onTap, }); @override State<RingButton> createState() => _RingButtonState(); } class _RingButtonState extends State<RingButton> { bool _isSelected = false; double _progress = 0.0; @override void initState() { super.initState(); _progress = widget.initialProgress; } @override Widget build(BuildContext context) { return GestureDetector( onTap: () { setState(() { _isSelected = !_isSelected; // 模拟进度变化,实际可根据业务逻辑设置具体值 _progress = _isSelected ? 0.75 : 0.0; }); widget.onTap?.call(); }, child: Container( width: 60, height: 60, child: Stack( alignment: Alignment.center, children: [ CustomPaint( painter: RingButtonPainter( progress: _progress, ringColor: widget.ringColor, progressColor: widget.progressColor, isSelected: _isSelected, ), size: Size.infinite, ), Icon( widget.icon, color: _isSelected ? widget.progressColor : widget.iconColor, size: 28, ), ], ), ), ); } }
使用示例
Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ RingButton(icon: Icons.home), RingButton(icon: Icons.favorite, progressColor: Colors.red), RingButton(icon: Icons.settings, progressColor: Colors.green), ], )
你可以根据需求调整strokeWidth、尺寸、颜色、进度值,以及点击后的状态变化逻辑,完全匹配你需要的按钮式环形饼图样式。
内容的提问来源于stack exchange,提问作者DholaSain
相关产品推荐
相关产品推荐

