实现动画的步骤和前文中提到的使用 FadeTransition、SizeTransition、SlideTransition等AnimatedWidget类似。
完整的代码
class NumAnimationPage extends StatefulWidget {
const NumAnimationPage({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() => _NumAnimationPageState();
}
class _NumAnimationPageState extends State<NumAnimationPage>
with SingleTickerProviderStateMixin {
/// 持续时间为5秒的动画控制器
late final AnimationController _controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 5),
)..forward();
/// 数字从100 到 99999的补间动画
late final Animation<num> _animation =
Tween<num>(begin: 100, end: 99999).animate(_controller);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
// 是一个AnimatedWidget,可自定义动画效果
child: AnimatedBuilder(
animation: _animation,
builder: (context, child) {
return Text(
// 忽略小数点
_animation.value.toStringAsFixed(0),
style: const TextStyle(color: Colors.red, fontSize: 48),
);
},
),
),
);
}
}
动画效果
自定义补间动画,接收的参数是字符串,返回的值是某个时刻对应的字符串内容。
class TextTween extends Tween<String> {
TextTween({String end = ''}) : super(begin: '', end: end);
@override
String lerp(double t) {
// 在动画过程中 t 的值是从 0 到 1
var cutoff = (end!.length * t).round();
// 返回动画时钟t时刻 对应的文字。
return end!.substring(0, cutoff);
}
}
这里用到了2个AnimationController的函数
class CustomTextAnimationPage extends StatefulWidget {
const CustomTextAnimationPage({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() => _CustomTextAnimationPageState();
}
class _CustomTextAnimationPageState extends State<CustomTextAnimationPage>
with SingleTickerProviderStateMixin {
final String _text = '风急天高猿啸哀,渚清沙白鸟飞回。'
'\n无边落木萧萧下,不尽长江滚滚来。'
'\n万里悲秋常作客,百年多病独登台。'
'\n艰难苦恨繁霜鬓,潦倒新停浊酒杯。';
/// 持续时间为10秒的动画控制器
late final AnimationController _controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 10),
)..forward();
late final Animation<String> _animation =
TextTween(end: _text).animate(_controller);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
AnimatedBuilder(
animation: _animation,
builder: (context, child) {
return Text(
_animation.value,
style: const TextStyle(
fontSize: 20, fontWeight: FontWeight.bold),
);
},
),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
tooltip: '重复一次',
onPressed: () {
_controller.forward(from: 0);
},
icon: const Icon(Icons.repeat_one),
),
IconButton(
tooltip: '删除古诗',
onPressed: () {
_controller.reverse();
},
icon: const Icon(Icons.delete),
)
],
),
],
),
),
);
}
}