让Widget
动起来
1.使用Animation
原理类似于Android
的属性动画,和Widget
分离,在一定时间内生成一系列的值,值可以是int
,double
,color
或者string
等等,每隔N毫秒,或者N秒钟获取到最新的值去替换掉Widget
上的值,同时刷新布局,如果刷新间隔足够小就能起到动画的作用,例如构造一个Widget
,他的width
,height
由动画来控制,一定时间动态更新值使Widget
产生动效:
new Container( margin: new EdgeInsets.symmetric(vertical: 10.0), height: animation.value, width: animation.value, child: new FlutterLogo(), ),复制代码
接下来看下如何使用Animation
构建一个动态更新Widget
的简单场景
- 导入
Animation
类import 'package:flutter/animation.dart';
- 创建
StatefulWidget
,创建Animation
的实现类AnimationController
,来构造一个最简单的属性动画,并且应用到Widget
上。
class TestPage extends StatefulWidget { @override _TestPageState createState() => _TestPageState();}class _TestPageState extends Statewith SingleTickerProviderStateMixin { AnimationController animationController; @override void initState() { // TODO: implement initState super.initState(); animationController = AnimationController( vsync: this, duration: Duration(milliseconds: 1000)); animationController.addListener(() { setState(() {}); }); animationController.forward(); //启动动画 } @override Widget build(BuildContext context) { print('tag' + animationController.value.toString()); return Center( child: Container( width: animationController.value, height: animationController.value * 100, color: Colors.red, ), ); }}复制代码
可以看到回调打印的是从0-1的值,要返回其他类型的数值就需要用到Tween
,Tween
有许多子类例如:
class _TestPageState extends Statewith SingleTickerProviderStateMixin { AnimationController animationController; Animation animation; @override void initState() { // TODO: implement initState super.initState(); animationController = AnimationController( vsync: this, duration: Duration(milliseconds: 1000)); animation = Tween(begin: 0.0,end: 100.0).animate(animationController); animationController.addListener(() { setState(() {}); }); animationController.forward(); //启动动画 } @override Widget build(BuildContext context) { print('tag' + animationController.value.toString()); return Center( child: Container( width: animation.value.toDouble(), height: animation.value.toDouble() , color: Colors.red, ), ); }}复制代码
2.使用AnimatedWidget
来简化代码AnimatedWidget
,省去了addListener()
以及setState()
交给AnimatedWidget
处理,感觉也没省掉很多。。
class TestContainer extends AnimatedWidget { TestContainer({Key key,Animation animation}) : super(key: key, listenable: animation); @override Widget build(BuildContext context) { // TODO: implement build Animation animation = listenable; return Center( child: Container( width: animation.value.toDouble(), height: animation.value.toDouble() , color: Colors.red, ), ); }}class TestPage extends StatefulWidget { @override _TestPageState createState() => _TestPageState();}class _TestPageState extends Statewith SingleTickerProviderStateMixin { AnimationController animationController; Animation animation; @override void initState() { // TODO: implement initState super.initState(); animationController = AnimationController( vsync: this, duration: Duration(milliseconds: 1000)); animation = Tween(begin: 0.0,end: 100.0).animate(animationController); animationController.forward(); //启动动画 } @override Widget build(BuildContext context) { return TestContainer(animation: animation,); }}复制代码
3.使用AnimatedWidget
相关Api
来再次简化代码,例如使用RotationTransition
将Widget
在3秒钟内旋转360度
class TestPage extends StatefulWidget { @override _TestPageState createState() => _TestPageState();}class _TestPageState extends Statewith SingleTickerProviderStateMixin { AnimationController animationController; Animation animation; @override void initState() { // TODO: implement initState super.initState(); animationController = AnimationController( vsync: this, duration: Duration(seconds: 10)); animation = Tween(begin: 0.0, end: 1).animate(animationController); animationController.forward(); //启动动画 } @override Widget build(BuildContext context) { return RotationTransition(turns: animation, child: Center( child: Container(color: Colors.red, width: 100, height: 100,)),); }}复制代码
4.对动画过程进行监听
animation.addStatusListener((status) { if (status == AnimationStatus.completed) { controller.reverse(); } else if (status == AnimationStatus.dismissed) { controller.forward(); } });复制代码
5.使用AnimationBuilder
,将控件和动画的控制过程进行封装
class TestTransition extends StatelessWidget { TestTransition({this.child, this.animation}); final Widget child; final Animationanimation; Widget build(BuildContext context) { return new Center( child: new AnimatedBuilder( animation: animation, builder: (BuildContext context, Widget child) { return new Container( height: animation.value, width: animation.value, child: child); }, child: child), ); }}class TestPage extends StatefulWidget { @override _TestPageState createState() => _TestPageState();}class _TestPageState extends State with SingleTickerProviderStateMixin { AnimationController animationController; Animation animation; @override void initState() { // TODO: implement initState super.initState(); animationController = AnimationController(vsync: this, duration: Duration(seconds: 10)); animation = Tween(begin: 0.0, end: 100.0).animate(animationController); animationController.forward(); //启动动画 } @override Widget build(BuildContext context) { return TestTransition( child: Center( child: Container( color: Colors.red, )), animation: animation, ); }}复制代码