前言
在上一篇的動畫內容中,我們學習了基本的概念,以及動畫的基本使用規則,但是,上一篇的代碼真的實際項目中應用很多嗎?其實不是,上一篇之所以那麼介紹,只是爲了讓大家更瞭解Flutter動畫的原理,其實還有更簡單封裝與簡化的使用方式,這一篇就開始學習這些內容。
AnimatedWidget
前面動畫之中,我們都是通過addListener和setState來更新UI的,然而有時候可以不用這麼麻煩,通過AnimationWidget這個類就可以實現,它對addListener和setState進行了封裝,隱藏了實現細節。下面,我們直接上代碼來看看:
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin{
Animation<double> animation;
AnimationController controller;
initState(){
super.initState();
controller=AnimationController(duration: const Duration(milliseconds: 2000),vsync: this);
animation=CurvedAnimation(parent: controller,curve: Curves.bounceIn)..addStatusListener((status){
if(status==AnimationStatus.completed){//動畫在結束時停止的狀態
controller.reverse();//顛倒
}else if(status==AnimationStatus.dismissed){//動畫在開始時就停止的狀態
controller.forward();//向前
}
})..addListener((){
setState(() {
print(animation.value);
});
});
controller.forward();
}
@override
void dispose() {
controller.dispose();
// TODO: implement dispose
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimationLogo(animation: animation,);
}
}
class AnimationLogo extends AnimatedWidget{
AnimationLogo({Key key,Animation<double> animation})
:super(key:key,listenable:animation);
@override
Widget build(BuildContext context) {
final Animation<double> animation=listenable;
return Scaffold(
appBar: AppBar(
title: Text("封裝動畫"),
),
body: Container(
height: animation.value*300,
margin: EdgeInsets.symmetric(vertical: 10.0),
width: animation.value*300,
child: FlutterLogo(),
),
);
}
}
封裝後,AnimationLogo可以通過當前自身Animation的value值來繪製自己。
AnimatedBuilder
有時候我們會使用多個AnimatedWidget,而如果多次實現AnimatedWidget,則代碼就顯得不那麼美觀了,這個時候,我們就需要考慮使用AnimatedBuilder,它的優點有:
(1)不需要知道如何渲染組件,也不需要知道如何管理動畫對象
(2)繼承自AnimatedWidget,可以直接當作組件來使用,且不用顯式地去添加幀的監聽addListener(…),然後在調用setState
(3)只調用動畫組件中地build,在複雜地佈局下性能有所提高
我們先來看一張組件示意圖:
接着我們將上面的代碼進行重構,代碼如下:
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin{
Animation<double> animation;
AnimationController controller;
initState(){
super.initState();
controller=AnimationController(duration: const Duration(milliseconds: 2000),vsync: this);
animation=CurvedAnimation(parent: controller,curve: Curves.bounceIn)..addStatusListener((status){
if(status==AnimationStatus.completed){//動畫在結束時停止的狀態
controller.reverse();//顛倒
}else if(status==AnimationStatus.dismissed){//動畫在開始時就停止的狀態
controller.forward();//向前
}
})..addListener((){
setState(() {
});
});
controller.forward();
}
@override
void dispose() {
controller.dispose();
// TODO: implement dispose
super.dispose();
}
@override
Widget build(BuildContext context) {
return GrowTransition(child:AnimationLogo(),animation: animation,);
}
}
class AnimationLogo extends StatelessWidget{
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
margin: EdgeInsets.symmetric(vertical: 10),
child: FlutterLogo(),
);
}
}
class GrowTransition extends StatelessWidget{
final Widget child;
final Animation<double> animation;
GrowTransition({this.child,this.animation});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("AnimatedBuilder"),),
body: Center(
child: AnimatedBuilder(
animation: this.animation,
builder: (BuildContext context,Widget child){
return Container(
height: animation.value*300,
width: animation.value*300,
child: child,
);
},
child: this.child,
),
),
);
}
}
前面的代碼基本一樣,就是後面的代碼變更了,所以重點看後面的代碼就行。其實在Flutter開發中,通過AnimatedBuilder方式還封裝了很多動畫,比如SizeTransition,ScaleTransition,RotationTransition,FadeTransition,FractionalTranslation等。很多時候我們都可以反覆使用這些預置的過渡類。效果圖更前篇文章差不多,這裏就不展示了。