最近使用 Flutter 开发 App 时,做了一个圆环占比图,或者说统计图。但现在 UI 又把设计修改了,当时实现的控件被废弃没啥用。但我觉得这个圆环风格统计图设计的挺好看,万一后面还需要担心找不到,所以贴到博客来,可能还能帮到有需要的朋友。
圆环占比统计图 Widget 控件具体实现代码
import 'dart:math' as math;
/// 圆环占比统计图
class CustomCircle extends StatelessWidget {
final double offline, online, fault;
final String topText, bottomText;
final double size;
final Color offlineColor, onlineColor, faultColor;
CustomCircle({
this.offline = 0,
this.online = 0,
this.fault = 0,
this.topText = '',
this.bottomText = '',
this.size = 140,
this.offlineColor = Colors.grey,
this.onlineColor = Colors.green,
this.faultColor = Colors.red,
});
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
return Stack(
children: [
SizedBox(
height: size,
width: size,
child: CustomPaint(
painter: CirclePainter(offline, online, fault, offlineColor, onlineColor, faultColor),
),
),
Positioned(
top: size / 3,
child: Container(
width: size,
child: Text(topText, textAlign: TextAlign.center, style: Theme.of(context).textTheme.subtitle1,),
),
),
Positioned(
top: size / 2,
child: Container(
width: size,
child: Text(bottomText, textAlign: TextAlign.center, style: Theme.of(context).textTheme.bodyText1?.copyWith(fontWeight: FontWeight.bold,)),
),
),
],
);
},
);
}
}
class CirclePainter extends CustomPainter {
final double offline, online, fault;
final Color offlineColor, onlineColor, faultColor;
CirclePainter(
this.offline,
this.online,
this.fault,
this.offlineColor,
this.onlineColor,
this.faultColor,
);
@override
void paint(Canvas canvas, Size size) {
double startAngle = -math.pi / 2;
double total = offline + online + fault;
Paint offlinePaint = Paint()
..color = offlineColor
..strokeWidth = 14
..style = PaintingStyle.stroke
..strokeCap = StrokeCap.round;
Paint onlinePaint = Paint()
..color = onlineColor
..strokeWidth = 14
..style = PaintingStyle.stroke
..strokeCap = StrokeCap.round;
Paint faultPaint = Paint()
..color = faultColor
..strokeWidth = 14
..style = PaintingStyle.stroke
..strokeCap = StrokeCap.round;
canvas.drawCircle(size.center(Offset.zero), size.width / 2, offlinePaint);
if (online > 0) {
double sweepAngle = online / total * 2 * math.pi;
canvas.drawArc(
Rect.fromCircle(center: size.center(Offset.zero), radius: size.width / 2),
startAngle,
sweepAngle,
false,
onlinePaint);
}
if (fault > 0) {
double sweepAngle = fault / total * 2 * math.pi;
canvas.drawArc(
Rect.fromCircle(center: size.center(Offset.zero), radius: size.width / 2),
startAngle,
sweepAngle,
false,
faultPaint);
}
}
@override
bool shouldRepaint(CirclePainter oldDelegate) => false;
}
使用
Widget buildCirclePercent(BuildContext context, int offline, int online, int fault) {
return Container(
width: double.infinity,
padding: EdgeInsets.symmetric(vertical: 20),
child: Center(
child: CustomCircle(
offline: offline.toDouble(),
online: online.toDouble(),
fault: fault.toDouble(),
topText: '总数',
bottomText: '${offline+online+fault}',
size: 148,
offlineColor: Colors.grey,
onlineColor: Colors.green,
faultColor: Colors.red,
),
),
);
}
上面图片中我画了三个,分别代表不同情况的展示。
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'CustomCircle Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(title: Text("CustomCircle Demo")),
body: Column(
children: [
buildCirclePercent(context, 10, 20, 5),
buildCirclePercent(context, 6, 6, 0),
buildCirclePercent(context, 0, 0, 0),
],
), // 使用了示例数字
),
);
}
OK,希望以上内容能帮到你。
本文由老郭种树原创,转载请注明:https://guozh.net/flutter-ring-proportion-chart/