让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 State<TestPage>
with 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 State<TestPage>
with 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 State<TestPage>
with 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 State<TestPage>
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: 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 Animation<double> animation;
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<TestPage>
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,
);
}
}
网友评论