概述
花瓣App的轉(zhuǎn)場動畫,這么多年還是沒變,還是圖片轉(zhuǎn)場動畫.
網(wǎng)上有很多人實現(xiàn)過相關(guān)效果,先前騷棟18年在做iOS項目的時候,也實現(xiàn)的類似的效果,但是全程實現(xiàn)起來還是比較麻煩,需要自己來定義轉(zhuǎn)場動畫.在Flutter中也提供了相關(guān)效果的組件,那就是 <font color="#FF0000">Hero</font> . 接下來我們就來看一下Hero組件實現(xiàn)這種轉(zhuǎn)場動畫效果,整體來說還是比較簡單的.
Hero動畫
首先看一下Hero的構(gòu)建方法.
其中有兩個參數(shù)是必須要傳入的,一個是final Object tag;
,是兩個路由需要實現(xiàn)Hero動畫組件的唯一標識.另外一個就是final Widget child;
,是需要執(zhí)行動畫的具體視圖組件,可以是個頭像,圖片,文字等等都是可以的.
const Hero({
Key key,
@required this.tag,
this.createRectTween,
this.flightShuttleBuilder,
this.placeholderBuilder,
this.transitionOnUserGestures = false,
@required this.child,
}) : assert(tag != null),
assert(transitionOnUserGestures != null),
assert(child != null),
super(key: key);
接下來我們就以一個普通Container組件為例,看一下具有應(yīng)該怎么實現(xiàn)Hero動畫.
首先,我們先創(chuàng)建一個StatelessWidget - FlutterHeroAnimationFirstPage
,當做起始路由.在build構(gòu)建方法中,我們創(chuàng)建一個Hero組件和一個用于點擊跳轉(zhuǎn)的Button組件.Hero組件定義Tag值為HeroAnimationTag
.代碼如下所示,
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Hero(
tag: "HeroAnimationTag",
child: Container(
width: 100,
height: 100,
margin: EdgeInsets.only(bottom: 10),
color: Colors.redAccent,
),
),
FlatButton(
onPressed: (){_startHeroAnimation(context);},
child: Text(
"點擊執(zhí)行Hero動畫",
style: TextStyle(color: Colors.black38),
),
),
],
),
),
);
}
對于路由調(diào)轉(zhuǎn)方案,雖然使用其他路由形式也是可以的,但是這里我推薦使用 PageRouteBuilder + FadeTransition
兩者配合使用,具體路由跳轉(zhuǎn)方法_startHeroAnimation
代碼如下所示.
void _startHeroAnimation(BuildContext context) {
Navigator.push(context, PageRouteBuilder(
pageBuilder: (BuildContext context, Animation animation,
Animation secondaryAnimation) {
return new FadeTransition(
opacity: animation,
child: FlutterHeroAnimationSecondPage(),
);
})
);
}
然后第二路由中的Widget就比較簡單了. 在build構(gòu)建方法中, 依然需要創(chuàng)建一個Hero組件,并且Tag值要與先前的保持一致.當然了,這里我也創(chuàng)建了一個Button,用于返回上一個路由.具體代碼如下所示.
class FlutterHeroAnimationSecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Hero(
tag: "HeroAnimationTag",
child: Container(
height: 100,
margin: EdgeInsets.only(bottom: 10, left: 0, right: 0),
color: Colors.redAccent,
),
),
FlatButton(
onPressed: () {Navigator.pop(context);},
child: Text(
"點擊返回",
style: TextStyle(color: Colors.black38),
),
),
],
),
),
);
}
}
Hero動畫實現(xiàn)效果如下所示.
整體示例代碼
整體代碼實現(xiàn)比較簡單,這里就不傳Github了,直接貼出來了.具體如下所示.
class FlutterHeroAnimationFirstPage extends StatelessWidget {
void _startHeroAnimation(BuildContext context) {
Navigator.push(context, PageRouteBuilder(
pageBuilder: (BuildContext context, Animation animation,
Animation secondaryAnimation) {
return new FadeTransition(
opacity: animation,
child: FlutterHeroAnimationSecondPage(),
);
})
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Hero(
tag: "HeroAnimationTag",
child: Container(
width: 100,
height: 100,
margin: EdgeInsets.only(bottom: 10),
color: Colors.redAccent,
),
),
FlatButton(
onPressed: (){_startHeroAnimation(context);},
child: Text(
"點擊執(zhí)行Hero動畫",
style: TextStyle(color: Colors.black38),
),
),
],
),
),
);
}
}
class FlutterHeroAnimationSecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Hero(
tag: "HeroAnimationTag",
child: Container(
height: 100,
margin: EdgeInsets.only(bottom: 10, left: 0, right: 0),
color: Colors.redAccent,
),
),
FlatButton(
onPressed: () {Navigator.pop(context);},
child: Text(
"點擊返回",
style: TextStyle(color: Colors.black38),
),
),
],
),
),
);
}
}
結(jié)語
Hero動畫實現(xiàn)過程比較簡單,所有的工作都是由Flutter內(nèi)部幫我們完成的,Flutter Framework知道新舊路由頁中共享元素的位置和大小,所以根據(jù)這兩個端點,在動畫執(zhí)行過程中求出過渡時的插值(中間態(tài))即可.
歡迎持續(xù)關(guān)注騷棟,有任何問題歡迎聯(lián)系騷棟.