
老孟導讀:此篇文章是 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(一半)開始到結束,如果影片時長為6秒,_sizeAnimation則從第3秒開始,
Interval中begin 和end引數值的范圍是0.0到1.0,
下面實作一個先執行顏色變化,在執行大小變化,代碼如下:
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();
}
}
效果如下:

我們也可以設定同時影片,只需將2個Interval的值都改為Interval(0.0, 1.0),
想象下面的場景,一個紅色的盒子,影片時長為6秒,前40%的時間大小從100->200,然后保持200不變20%的時間,最后40%的時間大小從200->300,這種效果通過TweenSequence實作,代碼如下:
_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的權重,
最終效果如下:

共享影片
Hero是我們常用的過渡影片,當用戶點擊一張圖片,切換到另一個頁面時,這個頁面也有此圖,那么使用Hero組件就在合適不過了,先看下Hero的效果圖:

上面效果實作的串列頁面代碼如下:
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引數一致,
路由影片
轉場 就是從當前頁面跳轉到另一個頁面,跳轉頁面在 Flutter 中通過 Navigator,跳轉到新頁面如下:
Navigator.push(context, MaterialPageRoute(builder: (context) {
return _TwoPage();
}));
回退到前一個頁面:
Navigator.pop(context);
Flutter 提供了兩個轉場影片,分別為 MaterialPageRoute 和 CupertinoPageRoute,MaterialPageRoute 根據不同的平臺顯示不同的效果,Android效果為從下到上,iOS效果為從左到右,CupertinoPageRoute 不分平臺,都是從左到右,
使用 MaterialPageRoute 案例如下:
class NavigationAnimation extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: OutlineButton(
child: Text('跳轉'),
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效果:

如果要自定義轉場影片如何做?
自定義任何組件都是一樣的,如果系統有類似的,直接看源代碼是如何實作的,然后按照它的模版自定義組件,
回到正題,看 MaterialPageRoute 的繼承關系:

PageRoute 的繼承關系:

MaterialPageRoute 和 CupertinoPageRoute 都是繼承PageRoute,所以重點是 PageRoute,PageRoute 是一個抽象類,其子類還有一個 PageRouteBuilder,看其名字就知道這是一個可以自定義影片效果,PageRouteBuilder源代碼:

pageBuilder 表示跳轉的頁面,
transitionsBuilder 表示頁面的影片效果,默認值代碼:
Widget _defaultTransitionsBuilder(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
return child;
}
通過源代碼發現,默認情況下沒有影片效果,
自定義轉場影片只需修改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()));
不僅是這些平移影片,前面所學的旋轉、縮放等影片直接替換 SlideTransition 即可,
上面的影片只對新的頁面進行了影片,如果想實作當前頁面被新頁面從頂部頂出的效果,實作方式如下:
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,
)
],
),
);
}
本質就是對兩個頁面做影片處理,使用:
Navigator.push(context, CustomPageRoute(this, _TwoPage()));

除了自定義路由影片,在 Flutter 1.17 發布大會上,Flutter 團隊還發布了新的 Animations 軟體包,該軟體包提供了實作新的 Material motion 規范的預構建影片,
里面提供了一系列影片,部分效果:


詳情:https://juejin.im/post/6847902223909781511
交流
老孟Flutter博客地址(330個控制元件用法):http://laomengit.com
歡迎加入Flutter交流群(微信:laomengit)、關注公眾號【老孟Flutter】:
![]() |
![]() |
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/299.html
標籤:Dart


