Flutter 路由知識
[TOC]
1. Navigator
Navigator
是一個路由管理的元件,它提供了開啟和退出路由頁方法。Navigator
通過一個棧來管理活動路由集合。
Flutter分匿名路由與命名路由,比如直接使用Navigator.push
就是匿名路由跳轉, 使用Navigator.pushName
就是使用命名路由跳轉。
很多跳轉方法只有命名路由才能用, 推薦使用命名路由。
路由表
使用命名路由, 必須要先提供並註冊一個路由表, 這樣應用程式才知道哪個名字與哪個路由元件相對應。其實註冊路由表就是給路由定義個名字, 路由表定義如下:
Map<String, WidgetBuilder> routes;
typedef WidgetBuilder = Widget Function(BuildContext context);
複製程式碼
這是一個Map
, key值為路由的名字, 型別是String
, value是個builder回撥函式, 用於生成對應的路由widget。
在通過命名路由進行跳轉的時候, 程式會根據路由名字在路由表中查詢到對應的WidgetBuilder
回撥函式, 然後呼叫該回撥函式生成路由widget並返回。
路由表的需要在MaterialApp
下, 新增routes
屬性或者在onGenerateRoute引數中新增。
MaterialApp(
title: 'Flutter Demo',
initialRoute:"/", //名為"/"的路由作為應用的home(首頁)
routes:{//註冊路由表
'testPage':(context) => TestPage(),
'/':(context) => HomePage(),
} ,
);
複製程式碼
命令路由傳遞引數
比如說Navigator.pushNamed(BuildContext context, String routeName, {Object arguments});
引數是arguments
, 型別是Object
, 一般我們使用的時候都是用Map<String, dynamic>
下面是使用方法
建立一個有引數的頁面:
class ParamPage extends StatelessWidget {
final int index;
final List<String> list;
final TestParam testParam;
const ParamPage({Key key, this.index, this.list, this.testParam}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('有引數的路由',),),
body: Center(
child: OutlinedButton(
onPressed: (){
print(index);
print(list);
print(testParam.text);
},
child: Text('點選'),
),
),
);
}
}
class TestParam{
int i;
String text;
TestParam(this.i, this.text);
}
複製程式碼
在路由表中定義:
MaterialApp(
title: 'Flutter Demo',
routes:{//註冊路由表
'testPage':(context) => TestPage(),
'paramPage': (context){
final Map<String, dynamic> args = ModalRoute.of(context).settings.arguments;
return ParamPage(
index: args['index'],
list: args['list'],
testParam: args['testParam'],
);
}
} ,
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
複製程式碼
也能在MaterialApp的onGenerateRoute引數中定義:
MaterialApp(
title: 'Flutter Demo',
onGenerateRoute: (RouteSettings settings) {
if(settings.name == 'paramPage'){
final Map<String, dynamic> args = settings.arguments as Map<String, dynamic>;
return ParamPage(
index: args['index'],
list: args['list'],
testParam: args['testParam'],
);
}
}
home: MyHomePage(title: 'DemoPage'),
);
複製程式碼
開啟命名路由頁面, 並傳遞引數:
Navigator.pushNamed(
context,
'paramPage',
arguments: <String, dynamic>{
'index': 1,
'list': ['1', '2'],
'testParam': TestParam(1, 'text'),
},
);
複製程式碼
路由相關方法
通常當前螢幕顯示的頁面就是棧頂的路由。Navigator
提供了一系列方法來管理路由棧,下面整理列出常用的路由跳轉相關方法。
-
push: 跳轉到新頁面。
-
pushNamed: 跳轉到新頁面, 需要路由名。
-
pop: 關閉當前頁面, 返回到上個頁面。
-
canPop: 判斷是否可以導航到新頁面。
-
maybePop: 可能會導航到新頁面 ?( 暫時還不理解這個用法)。
-
pushReplacement: 替換當前路由。
-
pushReplacementNamed: 替換當前路由, 與上面一樣, 需要路由名。
-
popAndPushNamed: 關閉當前頁面, 再跳轉到新頁面。
-
pushAndRemoveUntil: 將給定路由推送到Navigator, 刪除先前路由直至該方法的predicate引數返回true為止。
-
pushNamedAndRemoveUntil: 與上面??那個方法一樣, 只不過替換成了命名路由。
-
popUntil: 反覆執行pop, 直到該方法的predicate引數返回true為止。
使用方法
-
push
方法詳情:
Navigator.push(BuildContext context, Route<T> route); 複製程式碼
此方法是將我們需要跳轉的頁面push到棧頂。引數context是上下文, 引數route我們使用MaterialPageRouter 或者 CupertinoPageRoute。
例項使用:
Navigator.push(context, MaterialPageRoute(builder: (context) => TestRoute2())); 複製程式碼
-
pushName
方法詳情:
Navigator.pushNamed( BuildContext context, String routeName, {Object arguments} ); 複製程式碼
此方法是將我們需要跳轉的頁面push到棧頂。routeName是定義好的路由名稱。
arguments為需要傳遞的引數。
例項使用:
Navigator.pushNamed(context, 'routeName'); 複製程式碼
-
pushReplacement
方法詳情:
Navigator.pushReplacement( BuildContext context, Route<T> newRoute, ); 複製程式碼
此方法是把當前頁面在棧中的位置替換成要跳轉的路由, 當新頁面進棧顯示後, 之前的頁面將執行dispose方法。
比如說1->2, 2到3的時候使用了pushReplacement, 在3按返回的時候是回到了1。
例項使用:
Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => TestRoute3()) ); 複製程式碼
-
pushReplacementNamed
方法詳情:
Navigator.pushReplacementNamed( BuildContext context, String routeName, {Object arguments, Object result} ); 複製程式碼
這個方法與上面??方法一樣, 只不過跳轉的路由換成路由名。
比如說1-->2, 2到3的時候使用了pushReplacementNamed, 在3按返回的時候是回到了1。
result為回撥給頁面1的引數, 在跳轉頁面1的方法後面加上.then((value){})就能接收到回撥引數。
例項使用:
Navigator.pushReplacementNamed(context, 'routeName'); 複製程式碼
-
popAndPushNamed
方法詳情:
Navigator.popAndPushNamed( BuildContext context, String routeName, {Object arguments, Object result} ); 複製程式碼
這個方法與上面??方法一樣, 區別是這個有pop關閉之前頁面的動畫, 關閉了這個頁面再跳轉到新頁面。
比如說1-->2, 2到3的時候使用了popAndPushNamed, 在3按返回的時候是回到了1。
result為回撥給頁面1的引數, 在跳轉頁面1的方法後面加上.then((value){})就能接收到回撥引數。
例項使用:
Navigator.popAndPushNamed( context, 'routeName', ); 複製程式碼
-
pushAndRemoveUntil
方法詳情:
Navigator.pushAndRemoveUntil( BuildContext context, Route<T> newRoute, RoutePredicate predicate, ); 複製程式碼
例如說一個購物支付例子, 可能會有首頁1->挑選商品頁2->填寫訂單3->支付確認頁4->支付成功頁5, 一旦使用者完成了支付事件, 這次訂單支付相關頁面都應該從路由棧中刪除, 在支付成功頁5按返回應該回到首頁1。
1-->2-->3-->4, 在4進入5時使用pushAndRemoveUntil(context, MaterialPageRoute(builder: (context) => TestRoute5()), ModalRoute.withName('testRoute1'));
這時候如果在頁面5點選返回, 將會回到頁面1。
例項使用:
Navigator.pushAndRemoveUntil( context, MaterialPageRoute(builder: (context) => TestRoute5()), ModalRoute.withName('testRoute1'), ); 複製程式碼
-
pushNamedAndRemoveUntil
方法:
Navigator.pushNamedAndRemoveUntil( BuildContext context, String newRoute, RoutePredicate predicate, ); 複製程式碼
與上面??方法作用相同, 不同之處是新路由換成了路由名, 路由名需要程式入口指定。
1-->2-->3-->4, 在4進入5時使用pushNamedAndRemoveUntil
這時候如果在頁面5點選返回, 將會回到頁面1。
例項使用:
Navigator.pushNamedAndRemoveUntil( context, 'testRoute5', ModalRoute.withName('testRoute1'), ); 複製程式碼
-
popUntil
方法詳情:
Navigator.popUntil(BuildContext context, RoutePredicate predicate); 複製程式碼
例如說一個登入註冊, 註冊需要邀請碼的例子, 從首頁1跳轉到登入頁2, 輸入賬號發現賬號未註冊, 然後跳轉到填寫邀請碼頁面3, 在邀請碼頁面3填寫完後需要直接回到首頁, 在進入到邀請碼頁面3時又不能使用pushReplacement方法, 因為邀請碼頁面3還需要返回到登入頁2, 這時候在邀請碼頁面3回到首頁的時候可以使用
Navigator.popUntil(context, ModalRoute.withName('testRoute1'));
這時候會直接回到首頁1
1-->2-->3, 在頁面3使用popUntil(context, ModalRoute.withName('testRoute1'), 會直接回到首頁1
例項使用:
Navigator.popUntil( context, ModalRoute.withName('testRoute1'), ); 複製程式碼