介绍一下:
该组件是显示类似在线人数或累计人数可滚动式的 Animation Widget
可以通过 Controller
控制里面的数字
没有gif(是懒 ←,←),总之就是一个可以自定义样式的数字,数字变化时会上下滚动
多的不说,先上 code。
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class DigitCounterController extends ValueNotifier<int>{
DigitCounterController(int initialValue) : super(initialValue);
bool _dispose = false;
@override
void dispose() {
_dispose = true;
super.dispose();
}
void setValue(int newValue){
if (!_dispose) {
value += newValue;
}
}
void resetValue(int newValue){
if (!_dispose) {
value = newValue;
}
}
}
class MultipleDigitCounter extends StatefulWidget {
final DigitCounterController controller;
final TextStyle textStyle;
final BoxDecoration boxDecoration;
MultipleDigitCounter({Key key, this.textStyle, this.controller, this.boxDecoration,}): super(key: key);
@override
MultipleDigitCounterState createState() {
return MultipleDigitCounterState();
}
}
class MultipleDigitCounterState extends State<MultipleDigitCounter> {
int get digits => _value.toString().length;
final List<SingleDigitCounter> animatedDigits = [];
int _value;
String _oldValue;
int get value => _value;
set value(int newValue) {
_oldValue = value.toString();
_value = newValue;
if (mounted) {
setState(() {});
}
}
String getValueAsString() => _value.toString();
@override
void initState() {
super.initState();
_oldValue = _value.toString();
widget.controller.addListener(_onListenChangeValue);
}
@override
void dispose() {
widget.controller.removeListener(_onListenChangeValue);
super.dispose();
}
void _onListenChangeValue(){
value = widget.controller.value;
}
@override
Widget build(BuildContext context) {
String newValue = getValueAsString();
if (newValue.length == animatedDigits.length ) {
for (var i = 0; i < newValue.length; i++) {
if (i < _oldValue.length) {
final old = _oldValue[i];
final curr = newValue[i];
if (old != curr) {
final sdsKey = animatedDigits[i].key as GlobalKey<_SingleDigitCounterState>;
sdsKey.currentState.setValue(int.parse(curr));
}
}
}
}
else{
animatedDigits.clear();
for (var i = 0; i < newValue.length; i++) {
var initialDigit = int.parse(newValue[i]);
if (i < _oldValue.length) {
final String old = _oldValue[i];
final String curr = newValue[i];
initialDigit = int.parse(old != curr ? curr : old);
animatedDigits.add(
SingleDigitCounter(
initialValue: initialDigit,
textStyle: widget.textStyle,
boxDecoration: widget.boxDecoration,
)
);
}
else{
animatedDigits.add(
SingleDigitCounter(
initialValue: initialDigit,
textStyle: widget.textStyle,
boxDecoration: widget.boxDecoration,
)
);
}
}
}
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: animatedDigits
);
}
}
class SingleDigitCounter extends StatefulWidget {
final TextStyle textStyle;
final BoxDecoration boxDecoration;
final int initialValue;
SingleDigitCounter({
this.boxDecoration: const BoxDecoration(color: Colors.black),
this.textStyle: const TextStyle(color: Colors.grey, fontSize: 30),
this.initialValue: 0
}): super(key: GlobalKey<_SingleDigitCounterState>());
@override
State<StatefulWidget> createState() {
return _SingleDigitCounterState();
}
}
class _SingleDigitCounterState extends State<SingleDigitCounter> {
TextStyle get _textStyle => widget.textStyle;
BoxDecoration get _boxDecoration => widget.boxDecoration;
Size digitSize;
int currentValue;
ScrollController scrollController = ScrollController();
@override
void initState() {
currentValue = widget.initialValue
digitSize = _getSingleDigitCounterSize();
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
animateTo();
});
}
void setValue(newValue) {
_setValue(newValue);
}
void animateTo() {
scrollController.animateTo(currentValue * digitSize.height, duration: const Duration(milliseconds: 300), curve: Curves.easeInOut);
}
@override
void dispose() {
scrollController.dispose();
super.dispose();
}
_setValue(int newValue) {
this.currentValue = newValue;
animateTo();
}
@override
Widget build(BuildContext context) {
return AbsorbPointer(
absorbing: true,
child: Container(
width: digitSize.width, height: digitSize.height,
decoration: _boxDecoration,
child: ListView(
controller: scrollController,
padding: EdgeInsets.zero,
children: <Widget>[
for (var i = 0; i < 10; i++)
SizedBox.fromSize(
size: digitSize,
child: Center(child: Text(i.toString(), style: _textStyle)),
)
],
),
),
);
}
Size _getSingleDigitCounterSize() {
TextPainter painter = TextPainter(
textDirection: TextDirection.ltr,
text: TextSpan(
text: "0",
style: _textStyle
)
);
painter.layout();
return painter.size;
}
}
使用示例代码:
- 声明一个数字控制器
final DigitCounterController controller = DigitCounterController(0); // 0 是初始值
- 布局
// 布局
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Center(
child: MultipleDigitCounter(
controller: controller,
textStyle: TextStyle(fontSize: 26, color: Color(0xFFFB8C2E))
)
)
)
);
}
- 控制器 api
//原有基础上累加数字
controller.setValue(520);
//重置数字
controller.resetValue(1314);
<・)))><<
以上代码可以随意 copy, 吃瓜~
祝大家开心每一天(▽)