詳解Android?Flutter如何自定義動(dòng)畫路由
簡(jiǎn)介
flutter中有默認(rèn)的Route組件,叫做MaterialPageRoute,一般情況下我們?cè)趂lutter中進(jìn)行跳轉(zhuǎn)的話,只需要向Navigator中傳入一個(gè)MaterialPageRoute就可以了。
但是MaterialPageRoute太普通了,如果我們想要做點(diǎn)不同的跳轉(zhuǎn)特效應(yīng)該如何處理呢?
一起來(lái)看看吧。
自定義跳轉(zhuǎn)使用
正常情況下,我們進(jìn)行路由跳轉(zhuǎn)需要用到Navigator和MaterialPageRoute,如下所示:
Navigator.push(context, MaterialPageRoute(builder: (context) {
return const NextPage();
如果要實(shí)現(xiàn)特定的路由動(dòng)畫,那么需要進(jìn)行路由的自定義。
在flutter中也就是要使用PageRouteBuilder來(lái)自定義一個(gè)Route。
先來(lái)看下PageRouteBuilder的定義:
class PageRouteBuilder<T> extends PageRoute<T> {
PageRouteBuilder({
super.settings,
required this.pageBuilder,
this.transitionsBuilder = _defaultTransitionsBuilder,
this.transitionDuration = const Duration(milliseconds: 300),
this.reverseTransitionDuration = const Duration(milliseconds: 300),
this.opaque = true,
this.barrierDismissible = false,
this.barrierColor,
this.barrierLabel,
this.maintainState = true,
super.fullscreenDialog,
})PageRouteBuilder也是PageRoute的一種,在構(gòu)建PageRouteBuilder的時(shí)候,通過(guò)控制不同的屬性值,我們可以自由控制pageBuilder,transitionsBuilder,transitionDuration,reverseTransitionDuration等特性。
可以看到自由程度還是非常高的。
其中pageBuilder是路由將會(huì)跳轉(zhuǎn)的頁(yè)面,這個(gè)是必須要指定的,要不然路由也就沒(méi)有意義了。
另外路由轉(zhuǎn)換的效果可以經(jīng)由transitionsBuilder來(lái)設(shè)置。
這里的RouteTransitionsBuilder是一個(gè)Function,返回一個(gè)Widget:
typedef RouteTransitionsBuilder = Widget Function(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child);
所以理論上,我們可以返回任何widget,但是一般來(lái)說(shuō),我們會(huì)返回一個(gè)AnimatedWidget,表示一個(gè)動(dòng)畫效果。
flutter動(dòng)畫基礎(chǔ)
flutter中有個(gè)專門的動(dòng)畫包叫做flutter/animation.dart, flutter中所有動(dòng)畫的核心叫做Animation。
Animation中定義了很多l(xiāng)istener用來(lái)監(jiān)控動(dòng)畫的變動(dòng)情況,并且還提供了一個(gè)AnimationStatus來(lái)存儲(chǔ)當(dāng)前的動(dòng)畫狀態(tài):
abstract class Animation<T> extends Listenable implements ValueListenable<T> {
const Animation();
AnimationWithParentMixin<T>
@override
void addListener(VoidCallback listener);
@override
void removeListener(VoidCallback listener);
void addStatusListener(AnimationStatusListener listener);
void removeStatusListener(AnimationStatusListener listener);
AnimationStatus get status;
AnimationStatus是一個(gè)枚舉類,它包含了現(xiàn)在動(dòng)畫的各種狀態(tài):
enum AnimationStatus {
dismissed,
forward,
reverse,
completed,
}dismissed表示動(dòng)畫暫停在開頭。
forward表示動(dòng)畫在從頭到尾播放。
reverse表示動(dòng)畫在從尾到頭播放。
completed表示動(dòng)畫播放完畢,停在了結(jié)尾。
有了動(dòng)畫的表示之后,如何對(duì)動(dòng)畫進(jìn)行控制呢?這里就需要用到AnimationController了。
AnimationController可以控制動(dòng)畫的duration,動(dòng)畫的最低值lowerBound默認(rèn)是0.0,動(dòng)畫的最高值upperBound默認(rèn)是1.0等等。
默認(rèn)情況AnimationController中從最低值到最高值是線性變化的,如果你想設(shè)置不同的Bound值,那么可以嘗試自定義 Animatable, 如果你想動(dòng)畫的變動(dòng)是非線性的,那么可以嘗試?yán)^承Animation來(lái)實(shí)現(xiàn)自己的變動(dòng)曲線。
實(shí)現(xiàn)一個(gè)自定義的route
這里我們使用flutter中的SlideTransition,SlideTransition是一個(gè)AnimatedWidget,它表示的是一個(gè)組件的位置變化的動(dòng)畫。
class SlideTransition extends AnimatedWidget {
const SlideTransition({
super.key,
required Animation<Offset> position,
this.transformHitTests = true,
this.textDirection,
this.child,
}) : assert(position != null),
super(listenable: position);
看下它的構(gòu)造函數(shù),可以看到SlideTransition需要一個(gè)position的屬性,這個(gè)position是一個(gè)Animation對(duì)象,里面包含的是Offset。
同時(shí)這個(gè)position是一個(gè)listenable對(duì)象,通過(guò)監(jiān)聽里面Offset的變化,從而重新build對(duì)應(yīng)的widget從而實(shí)現(xiàn)動(dòng)畫的效果。
Offset是一個(gè)表示位置的類,(0,0) 表示這個(gè)widget的左頂點(diǎn)在屏幕的左上角,同樣的(1,1)表示這個(gè)widget的左頂點(diǎn)在屏幕的右下角。
因?yàn)閞oute過(guò)后是一個(gè)新的頁(yè)面,我們希望出現(xiàn)一個(gè)頁(yè)面從右下角移動(dòng)到左上角的動(dòng)畫,那么我們可以這樣做:
Route customRoute() {
return PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) => const SecondPage(),
transitionsBuilder: (context, animation, secondaryAnimation, child) {
const begin = Offset(1.0, 1.0);
const end = Offset.zero;
const curve = Curves.easeOut;
var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
return SlideTransition(
position: animation.drive(tween),
child: child,
);
},
);
}這里的begin和end表示widget從屏幕的右下角移動(dòng)到了屏幕的左上角。
Tween表示的是開始值和結(jié)束值之間的線性插值,是一個(gè)動(dòng)態(tài)過(guò)程,另外我們還可以這個(gè)插值變動(dòng)的曲線,這里使用了CurveTween,選中了Curves.easeOut這種曲線類型。
最后調(diào)用animation.drive方法把Tween和Animation關(guān)聯(lián)起來(lái),這樣一個(gè)路由動(dòng)畫就完成了。
總結(jié)
最后程序運(yùn)行的結(jié)果如下:

其實(shí)flutter中的動(dòng)畫很簡(jiǎn)單,大家記住就是widget位置沿不同的曲線變化即可。
本文的例子:github.com/ddean2009/learn-flutter
以上就是詳解Android Flutter如何自定義動(dòng)畫路由的詳細(xì)內(nèi)容,更多關(guān)于Android Flutter自定義動(dòng)畫路由的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
在Android打包中區(qū)分測(cè)試和正式環(huán)境淺析
這篇文章主要給大家介紹了關(guān)于在Android打包中如何區(qū)分測(cè)試和正式環(huán)境的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起看看吧。2017-10-10
android判斷設(shè)備是否有相機(jī)的實(shí)例代碼
下面小編就為大家?guī)?lái)一篇android判斷設(shè)備是否有相機(jī)的實(shí)例代碼。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-03-03
Android App實(shí)現(xiàn)應(yīng)用內(nèi)部自動(dòng)更新的最基本方法示例
這篇文章主要介紹了實(shí)現(xiàn)Android App內(nèi)部自動(dòng)更新的最基本方法示例,包括IIS服務(wù)器端的簡(jiǎn)單布置,需要的朋友可以參考下2016-03-03
Android自定義控件實(shí)現(xiàn)優(yōu)雅的廣告輪播圖
這篇文章主要為大家詳細(xì)介紹了Android自定義控件實(shí)現(xiàn)優(yōu)雅的廣告輪播圖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03
Android ListView添加頭布局和腳布局實(shí)例詳解
這篇文章主要介紹了Android ListView添加頭布局和腳布局實(shí)例詳解的相關(guān)資料,大家看下效果是否是自己想要實(shí)現(xiàn)的效果,這里附了實(shí)現(xiàn)代碼和實(shí)現(xiàn)效果圖,需要的朋友可以參考下2016-11-11
Android 抽屜效果的導(dǎo)航菜單實(shí)現(xiàn)代碼實(shí)例
本篇文章主要介紹了Android 抽屜效果的導(dǎo)航菜單實(shí)現(xiàn)代碼實(shí)例,這種側(cè)滑的抽屜效果的菜單很好,有興趣的可以了解一下。2016-12-12
Android開發(fā)實(shí)現(xiàn)Launcher3應(yīng)用列表修改透明背景的方法
這篇文章主要介紹了Android開發(fā)實(shí)現(xiàn)Launcher3應(yīng)用列表修改透明背景的方法,結(jié)合實(shí)例形式分析了Launcher3相關(guān)配置文件與功能函數(shù)修改設(shè)置操作技巧,需要的朋友可以參考下2017-11-11
Android實(shí)現(xiàn)語(yǔ)音播放與錄音功能
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)語(yǔ)音播放與錄音功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07

