
因?yàn)楣P者本身主要從事是Android開發(fā),所以很多角度都是作為一個Android開發(fā)者學(xué)習(xí)Flutter的角度出發(fā),IOS或者H5的開發(fā)同學(xué)可以選擇性閱讀
目錄

前言
做Android開發(fā)的時候,要打開一個新的頁面,你得知道你的目標(biāo)頁面對象,然后初始化一個Intent或,再通過startActivity來打開一個新的頁面,不能跟web一樣,直接丟一個鏈接地址就跳轉(zhuǎn)到新的頁面。而Flutter的framework提供了類似路由跳轉(zhuǎn)的實(shí)現(xiàn)
靜態(tài)路由
- 靜態(tài)路由的注冊
MaterialApp組件中有一個字段routes參數(shù)來注冊路由,但是這里注冊的路由是靜態(tài)的,它不可以向下一個頁面?zhèn)鬟f參數(shù)
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: NavigatorPage(),
routes: <String, WidgetBuilder>{
'/router/first': (BuildContext context) => FirstPage(),
'/router/second': (BuildContext context) => SecondPage()
},
);
}
}
- 通過靜態(tài)路由跳轉(zhuǎn)(類似于Android中的
startActivity)
Navigator.pushNamed(context, "/router/first");
- 帶返回值的靜態(tài)路由(類似于Android中的
onActivityResult)
注意:靜態(tài)路由不能傳遞參數(shù)給下一個頁面,但是可以接收返回參數(shù)
Navigator.pushNamed(context, routeName).then((value){
//可以在這使用返回值value
});
- 返回上一個頁面(類似于Android中的
setResult+finish)
Navigator.of(context).pop('這是要返回給上一個頁面的數(shù)據(jù)');
動態(tài)路由
- 動態(tài)路由無需在
routes中注冊即可直接使用
Navigator.push(context, new MaterialPageRoute(builder: (context) {
return new FirstPage(title: '這是要傳遞給下一個頁面的參數(shù)');
}));
- 動態(tài)路由切換動畫
Material庫中提供了一個MaterialPageRoute,它可以使用和平臺風(fēng)格一致的路由切換動畫,如在iOS上會左右滑動切換,而在Android上會上下滑動切換。如果在Android上也想使用左右切換風(fēng)格,可以直接使用CupertinoPageRoute, 如:
Navigator.push(context, new CupertinoPageRoute(builder: (context) {
return new FirstPage();
}));
如果想自定義路由切換動畫,可以使用PageRouteBuilder,例如我們想以漸隱漸入動畫來實(shí)現(xiàn)路由過渡:
Navigator.push(context, PageRouteBuilder(
transitionDuration: Duration(milliseconds: 500), //動畫時間為500毫秒
pageBuilder: (BuildContext context, Animation animation,
Animation secondaryAnimation) {
return new FadeTransition( //使用漸隱漸入過渡,
opacity: animation,
child: FirstPage()
);
}));
}),
我們可以看到pageBuilder 有一個animation參數(shù),這是Flutter路由管理器提供的,在路由切換時pageBuilder在每個動畫幀都會被回調(diào),因此我們可以通過animation對象來自定義過渡動畫。
無論是MaterialPageRoute、CupertinoPageRoute,還是PageRouteBuilder,它們都繼承自PageRoute類,而PageRouteBuilder其實(shí)只是PageRoute的一個包裝,我們可以直接繼承PageRoute類來實(shí)現(xiàn)自定義路由,如下所示
定義一個路由類FadeRoute
class FadeRoute extends PageRoute {
FadeRoute({
@required this.builder,
this.transitionDuration = const Duration(milliseconds: 300),
this.opaque = true,
this.barrierDismissible = false,
this.barrierColor,
this.barrierLabel,
this.maintainState = true,
});
final WidgetBuilder builder;
@override
final Duration transitionDuration;
@override
final bool opaque;
@override
final bool barrierDismissible;
@override
final Color barrierColor;
@override
final String barrierLabel;
@override
final bool maintainState;
@override
Widget buildPage(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) => builder(context);
@override
Widget buildTransitions(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation, Widget child) {
return FadeTransition(
opacity: animation,
child: builder(context),
);
}
}
使用FadeRoute
Navigator.push(context, FadeRoute(builder: (context) {
return FirstPage();
}));
雖然上面的兩種方法都可以實(shí)現(xiàn)自定義切換動畫,但實(shí)際使用時應(yīng)考慮優(yōu)先使用PageRouteBuilder,這樣無需定義一個新的路由類,使用起來會比較方便。但是有些時候PageRouteBuilder是不能滿足需求的,例如在應(yīng)用過渡動畫時我們需要讀取當(dāng)前路由的一些屬性,這時就只能通過繼承PageRoute的方式了,舉個例子,假如我們只想在打開新路由時應(yīng)用動畫,而在返回時不使用動畫,那么我們在構(gòu)建過渡動畫時就必須判斷當(dāng)前路由isActive屬性是否為true,代碼如下:
@override
Widget buildTransitions(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation, Widget child) {
//當(dāng)前路由被激活,是打開新路由
if(isActive) {
return FadeTransition(
opacity: animation,
child: builder(context),
);
}else{
//是返回,則不應(yīng)用過渡動畫
return Padding(padding: EdgeInsets.zero);
}
}
總結(jié)
靜態(tài)路由和動態(tài)路由最大的差距就是動態(tài)路由可以向下一個頁面?zhèn)鬟f參數(shù),而靜態(tài)理由不可以。且動態(tài)路由可以設(shè)置路由切換的動畫