老孟導讀:此篇文章是 Flutter 動畫系列文章第四篇钉嘹,本文介紹動畫序列鸯乃、共享動畫、路由動畫跋涣。
動畫序列
Flutter中組合動畫使用Interval
缨睡,Interval
繼承自Curve
鸟悴,用法如下:
Animation _sizeAnimation = Tween(begin: 100.0, end: 300.0).animate(CurvedAnimation(
parent: _animationController, curve: Interval(0.5, 1.0)));
表示_sizeAnimation
動畫從0.5(一半)開始到結(jié)束,如果動畫時長為6秒宏蛉,_sizeAnimation
則從第3秒開始遣臼。
Interval
中begin
和end
參數(shù)值的范圍是0.0到1.0性置。
下面實現(xiàn)一個先執(zhí)行顏色變化拾并,在執(zhí)行大小變化,代碼如下:
class AnimationDemo extends StatefulWidget {
@override
State<StatefulWidget> createState() => _AnimationDemo();
}
class _AnimationDemo extends State<AnimationDemo>
with SingleTickerProviderStateMixin {
AnimationController _animationController;
Animation _colorAnimation;
Animation _sizeAnimation;
@override
void initState() {
_animationController =
AnimationController(duration: Duration(seconds: 5), vsync: this)
..addListener((){setState(() {
});});
_colorAnimation = ColorTween(begin: Colors.red, end: Colors.blue).animate(
CurvedAnimation(
parent: _animationController, curve: Interval(0.0, 0.5)));
_sizeAnimation = Tween(begin: 100.0, end: 300.0).animate(CurvedAnimation(
parent: _animationController, curve: Interval(0.5, 1.0)));
//開始動畫
_animationController.forward();
super.initState();
}
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
height: _sizeAnimation.value,
width: _sizeAnimation.value,
color: _colorAnimation.value),
],
),
);
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
}
效果如下:
我們也可以設(shè)置同時動畫鹏浅,只需將2個Interval
的值都改為Interval(0.0, 1.0)
嗅义。
想象下面的場景,一個紅色的盒子隐砸,動畫時長為6秒之碗,前40%的時間大小從100->200,然后保持200不變20%的時間季希,最后40%的時間大小從200->300褪那,這種效果通過TweenSequence實現(xiàn),代碼如下:
_animation = TweenSequence([
TweenSequenceItem(
tween: Tween(begin: 100.0, end: 200.0)
.chain(CurveTween(curve: Curves.easeIn)),
weight: 40),
TweenSequenceItem(tween: ConstantTween<double>(200.0), weight: 20),
TweenSequenceItem(tween: Tween(begin: 200.0, end: 300.0), weight: 40),
]).animate(_animationController);
weight
表示每一個Tween的權(quán)重式塌。
最終效果如下:
共享動畫
Hero是我們常用的過渡動畫博敬,當用戶點擊一張圖片,切換到另一個頁面時峰尝,這個頁面也有此圖偏窝,那么使用Hero組件就在合適不過了,先看下Hero的效果圖:
上面效果實現(xiàn)的列表頁面代碼如下:
class HeroDemo extends StatefulWidget {
@override
State<StatefulWidget> createState() => _HeroDemo();
}
class _HeroDemo extends State<HeroDemo> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, crossAxisSpacing: 5, mainAxisSpacing: 3),
children: List.generate(10, (index) {
if (index == 6) {
return InkWell(
onTap: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => new _Hero1Demo()));
},
child: Hero(
tag: 'hero',
child: Container(
child: Image.asset(
'images/bird.png',
fit: BoxFit.fitWidth,
),
),
),
);
}
return Container(
color: Colors.red,
);
}),
),
);
}
}
第二個頁面代碼如下:
class _Hero1Demo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
alignment: Alignment.topCenter,
child: Hero(
tag: 'hero',
child: Container(
child: Image.asset(
'images/bird.png',
),
),
)),
);
}
}
2個頁面都有Hero控件武学,且tag
參數(shù)一致祭往。
路由動畫
轉(zhuǎn)場 就是從當前頁面跳轉(zhuǎn)到另一個頁面,跳轉(zhuǎn)頁面在 Flutter 中通過 Navigator火窒,跳轉(zhuǎn)到新頁面如下:
Navigator.push(context, MaterialPageRoute(builder: (context) {
return _TwoPage();
}));
回退到前一個頁面:
Navigator.pop(context);
Flutter 提供了兩個轉(zhuǎn)場動畫硼补,分別為 MaterialPageRoute 和 CupertinoPageRoute,MaterialPageRoute 根據(jù)不同的平臺顯示不同的效果熏矿,Android效果為從下到上已骇,iOS效果為從左到右。CupertinoPageRoute 不分平臺曲掰,都是從左到右疾捍。
使用 MaterialPageRoute 案例如下:
class NavigationAnimation extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: OutlineButton(
child: Text('跳轉(zhuǎn)'),
onPressed: () {
Navigator.push(context, CupertinoPageRoute(builder: (context) {
return _TwoPage();
}));
},
),
),
);
}
}
class _TwoPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
color: Colors.blue,
),
);
}
}
iOS效果:
如果要自定義轉(zhuǎn)場動畫如何做?
自定義任何組件都是一樣的栏妖,如果系統(tǒng)有類似的乱豆,直接看源代碼是如何實現(xiàn)的,然后按照它的模版自定義組件吊趾。
回到正題宛裕,看 MaterialPageRoute 的繼承關(guān)系:
PageRoute 的繼承關(guān)系:
MaterialPageRoute 和 CupertinoPageRoute 都是繼承PageRoute瑟啃,所以重點是 PageRoute,PageRoute 是一個抽象類揩尸,其子類還有一個 PageRouteBuilder蛹屿,看其名字就知道這是一個可以自定義動畫效果,PageRouteBuilder源代碼:
pageBuilder
表示跳轉(zhuǎn)的頁面岩榆。
transitionsBuilder
表示頁面的動畫效果错负,默認值代碼:
Widget _defaultTransitionsBuilder(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
return child;
}
通過源代碼發(fā)現(xiàn),默認情況下沒有動畫效果勇边。
自定義轉(zhuǎn)場動畫只需修改transitionsBuilder
即可:
Navigator.push(
context,
PageRouteBuilder(pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
return _TwoPage();
}, transitionsBuilder: (BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) {
return SlideTransition(
position: Tween(begin: Offset(-1, 0), end: Offset(0, 0))
.animate(animation),
child: child,
);
}));
將其封裝犹撒,方便使用:
class LeftToRightPageRoute extends PageRouteBuilder {
final Widget newPage;
LeftToRightPageRoute(this.newPage)
: super(
pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) =>
newPage,
transitionsBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) =>
SlideTransition(
position: Tween(begin: Offset(-1, 0), end: Offset(0, 0))
.animate(animation),
child: child,
),
);
}
使用:
Navigator.push(context, LeftToRightPageRoute(_TwoPage()));
不僅是這些平移動畫,前面所學的旋轉(zhuǎn)粒褒、縮放等動畫直接替換 SlideTransition 即可识颊。
上面的動畫只對新的頁面進行了動畫,如果想實現(xiàn)當前頁面被新頁面從頂部頂出的效果奕坟,實現(xiàn)方式如下:
class CustomPageRoute extends PageRouteBuilder {
final Widget currentPage;
final Widget newPage;
CustomPageRoute(this.currentPage, this.newPage)
: super(
pageBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) =>
currentPage,
transitionsBuilder: (
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) =>
Stack(
children: <Widget>[
SlideTransition(
position: new Tween<Offset>(
begin: const Offset(0, 0),
end: const Offset(0, -1),
).animate(animation),
child: currentPage,
),
SlideTransition(
position: new Tween<Offset>(
begin: const Offset(0, 1),
end: Offset(0, 0),
).animate(animation),
child: newPage,
)
],
),
);
}
本質(zhì)就是對兩個頁面做動畫處理祥款,使用:
Navigator.push(context, CustomPageRoute(this, _TwoPage()));
除了自定義路由動畫,在 Flutter 1.17 發(fā)布大會上月杉,F(xiàn)lutter 團隊還發(fā)布了新的 Animations 軟件包刃跛,該軟件包提供了實現(xiàn)新的 Material motion 規(guī)范的預(yù)構(gòu)建動畫。
里面提供了一系列動畫沙合,部分效果:
詳情:https://juejin.im/post/6847902223909781511
交流
老孟Flutter博客地址(330個控件用法):http://laomengit.com
歡迎加入Flutter交流群(微信:laomengit)奠伪、關(guān)注公眾號【老孟Flutter】: