From 276874e07c01967681f24653cb5ed66cc2865cee Mon Sep 17 00:00:00 2001 From: debuggerx Date: Sun, 27 Nov 2022 16:00:18 +0800 Subject: [PATCH] implement inner ring. --- lib/main.dart | 102 ++++++++++++++++++++++++++++++++++++++---------- lib/ring_indicator.dart | 82 ++++++++++++++++++++++++++++++++------ 2 files changed, 153 insertions(+), 31 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index cee411e..10915f7 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -16,15 +16,9 @@ class MyApp extends StatelessWidget { title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, + brightness: Brightness.dark, ), - home: const FittedBox( - fit: BoxFit.fitWidth, - child: SizedBox( - width: 720, - height: 1080, - child: MyHomePage(title: 'Flutter Demo Home Page'), - ), - ), + home: const MyHomePage(title: 'Flutter Demo Home Page'), ); } } @@ -39,11 +33,15 @@ class MyHomePage extends StatefulWidget { } class _MyHomePageState extends State { - double value = 0; + double value1 = 30; + double value2 = 50; + double value3 = 10; void _incrementCounter() { setState(() { - value = Random().nextDouble() * 100; + value1 = Random().nextDouble() * 100; + value2 = Random().nextDouble() * 100; + value3 = Random().nextDouble() * 100; }); } @@ -58,23 +56,87 @@ class _MyHomePageState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ SizedBox.square( - dimension: 100, + dimension: 200, child: RingIndicator( ringColor: Colors.deepPurpleAccent, startAngel: pi * -0.7, endAngel: pi * 0.7, maxValue: 100, - value: value, - labelBuilder: (value) => Center( - child: Text( - value.toStringAsFixed(1), - style: const TextStyle(color: Colors.teal, fontSize: 24), - )), + value: value1, + labelBuilder: (values) { + return [ + const Align( + alignment: Alignment.bottomCenter, + child: Text( + 'CPU', + style: TextStyle(fontSize: 38), + ), + ), + Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text(values.level(0)?.toStringAsFixed(1) ?? '/', style: const TextStyle(fontSize: 18)), + Text(values.level(1)?.toStringAsFixed(1) ?? '/', style: const TextStyle(fontSize: 24)), + Text(values.level(2)?.toStringAsFixed(1) ?? '/', style: const TextStyle(fontSize: 18)), + ], + ), + ), + ]; + }, + innerRing: RingIndicator( + startAngel: pi * -0.7, + endAngel: pi * 0.7, + maxValue: 100, + ringColor: Colors.teal, + value: value2, + innerRing: RingIndicator( + startAngel: pi * -0.7, + endAngel: pi * 0.7, + ringColor: Colors.amber, + maxValue: 100, + value: value3, + ), + ), ), ), - Text( - '$value', - style: Theme.of(context).textTheme.headline4, + const SizedBox(height: 50), + SizedBox.square( + dimension: 200, + child: RingIndicator( + ringColor: Colors.teal, + startAngel: halfPi, + maxValue: 100, + value: value1, + labelBuilder: (values) => [ + const Align( + alignment: Alignment.topRight, + child: Text('RAM', style: TextStyle(fontSize: 38, height: 1.8)), + ), + Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text(values.level(2)?.toStringAsFixed(1) ?? '/', style: const TextStyle(fontSize: 18)), + Text(values.level(1)?.toStringAsFixed(1) ?? '/', style: const TextStyle(fontSize: 24)), + Text(values.level(0)?.toStringAsFixed(1) ?? '/', style: const TextStyle(fontSize: 18)), + ], + ), + ), + ], + innerRing: RingIndicator( + ringColor: Colors.deepOrange, + startAngel: halfPi, + maxValue: 100, + value: value2, + innerRing: RingIndicator( + ringColor: Colors.indigoAccent, + startAngel: halfPi, + maxValue: 100, + value: value3, + ), + ), + ), ), ], ), diff --git a/lib/ring_indicator.dart b/lib/ring_indicator.dart index e9c53e0..5224a7b 100644 --- a/lib/ring_indicator.dart +++ b/lib/ring_indicator.dart @@ -6,12 +6,33 @@ import 'package:flutter/scheduler.dart'; const halfPi = pi / 2; const pi = math.pi; -typedef LabelBuilder = Widget Function(double value); +typedef LabelBuilder = Iterable Function(List values); + +extension LevelValueExt on List { + double? level(int level) { + for (var element in this) { + if (element.level == level) return element.value; + } + return null; + } +} + +@immutable +class LevelValue { + final double value; + final int level; + + const LevelValue(this.value) : level = 0; + + const LevelValue._withLevel(this.value, this.level); + + LevelValue incrementLevel() => LevelValue._withLevel(value, level + 1); +} class RingIndicator extends StatefulWidget { const RingIndicator({ Key? key, - this.backgroundColor = Colors.grey, + this.backgroundColor = Colors.white12, this.ringWidth = 10, this.startAngel = 0, this.endAngel = pi * 2, @@ -21,7 +42,9 @@ class RingIndicator extends StatefulWidget { required this.value, this.innerRing, this.labelBuilder, - }) : super(key: key); + double? gap, + }) : gap = gap ?? ringWidth / 2, + super(key: key); final Color backgroundColor; final double ringWidth; @@ -33,19 +56,22 @@ class RingIndicator extends StatefulWidget { final double value; final RingIndicator? innerRing; final LabelBuilder? labelBuilder; + final double gap; @override State createState() => _RingIndicatorState(); } class _RingIndicatorState extends State { - double? _value = 0; + double _value = 0; + Map values = {}; + + _RingIndicatorState? parent; @override Widget build(BuildContext context) { - var value = _value ?? widget.value; var fillAngel = - ((value - widget.minValue) / (widget.maxValue - widget.minValue)) * (widget.endAngel - widget.startAngel); + ((_value - widget.minValue) / (widget.maxValue - widget.minValue)) * (widget.endAngel - widget.startAngel); return Center( child: SizedBox.expand( child: CustomPaint( @@ -59,7 +85,12 @@ class _RingIndicatorState extends State { ), child: Stack( children: [ - if (widget.labelBuilder != null) widget.labelBuilder!(value), + if (widget.innerRing != null) + Padding( + padding: EdgeInsets.all(widget.ringWidth + widget.gap), + child: widget.innerRing, + ), + if (widget.labelBuilder != null) ...widget.labelBuilder!(values.values.toList()), ], ), ), @@ -69,9 +100,7 @@ class _RingIndicatorState extends State { Ticker? ticker; - @override - void didUpdateWidget(RingIndicator oldWidget) { - super.didUpdateWidget(oldWidget); + _handleValueChange(double newValue, double oldValue) { var startTime = DateTime.now(); ticker?.stop(); ticker = Ticker((_) { @@ -81,12 +110,43 @@ class _RingIndicatorState extends State { } if (mounted) { setState(() { - _value = oldWidget.value + (widget.value - oldWidget.value) * (diff / 300); + _value = oldValue + (newValue - oldValue) * (diff / 300); + values[0] = LevelValue(_value); }); + if (parent != null) { + for (var value in values.values) { + parent!.updateValue(value.incrementLevel()); + } + } } }) ..start(); } + + @override + void initState() { + super.initState(); + _handleValueChange(widget.value, 0); + parent = context.findAncestorStateOfType<_RingIndicatorState>(); + } + + @override + void didUpdateWidget(RingIndicator oldWidget) { + super.didUpdateWidget(oldWidget); + _handleValueChange(widget.value, oldWidget.value); + } + + void updateValue(LevelValue value) { + values[value.level] = value; + if (parent != null && parent!.mounted) { + for (var value in values.values) { + parent!.updateValue(value.incrementLevel()); + } + } + if (mounted) { + setState(() {}); + } + } } class _RingIndicatorPainter extends CustomPainter {