Flutter的設計貌似對前端同學比較友好,言歸正傳,先從原理開始,然后是具體的case,好,我們開始:
小提示:電腦端閱讀更佳
1. 路由工作原理:
對于原來移動端開發的同學,多了件事情,管理路由。簡單講路由的工作原理是通過路由對象的進出棧來使用戶從一個頁面跳轉到另一個頁面。
2. 路由是什么?
在Flutter 中理解好路由(Route), 離不開另一個概念導航(Navigator), Flutter中路由管理, 主要依賴的是 Navigator(導航器)類, 這是一個用于管理一組具有某種進出規則的頁面的 Widget, 也就是說用它我們能夠實現各個頁面間有規律的切換, 而這里的規則便是在其內部維護的一個“ 路由棧。
3. 路由的種類:
路由分為 組件路由,命名路由,自定義路由,嵌套路由。
4. 使用方法:
Navigator:導航器,負責管理路由
路由名稱命名:路由名稱通常使用路徑結構:“/a/b/c”,主頁默認為 “/”。
4.1 PUSH 使用
1. pushNamed
Navigator.of(context).pushNamed('routeName');
簡單的將我們需要進入的頁面push到棧頂,以此來顯示當前頁面,其參數是一個字符串類型,傳入的是頁面對應的路由名稱 該路由名稱需要在程序主入口中進行定義:
void main() {
runApp(
new MaterialApp(
home: new Screen1(),
routes: <String, WidgetBuilder> {
'/screen1': (BuildContext context) => new Screen1(),
'/screen2': (BuildContext context) => new Screen2(),
'/screen3': (BuildContext context) => new Screen3(),
}, ));}
2.pushReplacementNamed
Navigator.of(context).pushReplacementNamed('routeName');
指把當前頁面在棧中的位置替換成跳轉的頁面(替換導航器的當前路由,通過推送路由[routeName]),當新的頁面進入后,之前的頁面將執行dispose方法。
下面為官方說明:
Replace the current route of the navigator that most tightly encloses the given context by pushing the route named [routeName] and then disposing the previous route once the new route has finished animating in.
Case Study:
從SplashScreen到HomeScreen。它應該只顯示一次,用戶不應該再從主屏幕回到它。在這種情況下,由于我們將要進入一個全新的屏幕, 我們可能想要使用這個方法來實現它的enter animation屬性。
3.pushReplacement
特點:可以通信,頁面間傳遞參數
Navigator.pushReplacement( context, MaterialPageRoute(builder: (BuildContext context) => screen4(param)));
4. popAndPushNamed
Navigator.popAndPushNamed(context, 'routeName');
指把當前頁面在棧中的位置替換成跳轉的頁面(替換導航器的當前路由,通過推送路由[routeName]),當新的頁面進入后,之前的頁面將執行dispose方法。
下面為官方說明:
Replace the current route of the navigator that most tightly encloses the given context by pushing the route named [routeName] and then disposing the previous route once the new route has finished animating in.
Case Study:
例如 在購物應用中,有產品列表,用戶在產品列表中可以通過篩選,來進一步選擇商品,在這個過程中,用戶點擊篩選按鈕時,會進入篩選條件選擇界面,當用戶點擊 確定篩選按鈕時,應彈出篩選界面,并使用新的篩選條件進入產品列表。這種情況popAndPushNamed就更合適了。
5. pushNamedAndRemoveUntil
Navigator.of(context).pushNamedAndRemoveUntil('routeName', (Route<dynamic> route) => false);
指將制定的頁面加入到路由中,然后將其他所有的頁面全部pop, (Route route) => false將確保刪除推送路線之前的所有路線。 這時候將打開一個新的routeName頁
Case Study:
使用情況:例如 當用戶點擊了退出登錄時,我們需要進入某一個頁面(比如點退出登錄后進入了登錄頁),這個時候用戶點擊返回時不應該能進入任何一個頁面,這種情況就可以使用。
6. pushAndRemoveUntil
Navigator.pushAndRemoveUntil( context, MaterialPageRoute(builder: (BuildContext context) => new screen4()), ModalRoute.withName('/'))
7. popUntil
Navigator.popUntil(context, ModalRoute.withName('routeName'));
4.2 POP 使用
1. maybePop
Navigator.of(context).maybePop();
maybePop 會自動進行判斷,如果當前頁面pop后,會顯示其他頁面,不會出現問題,則將執行當前頁面的pop操作 否則將不執行。
Case Study:
如果我們在初始路由上并且有人錯誤地試圖彈出這個唯一頁面怎么辦? 彈出堆棧中唯一的頁面將關閉您的應用程序,因為它后面已經沒有頁面了。這顯然是不好的體驗。 這就是 maybePop() 起的作用。
2.canPop
Navigator.of(context).canPop();
canPop 判斷當前頁面能否進行pop操作,并返回bool值
3.pop
Navigator.of(context).pop();
直接退出當前頁面
4.3 Popup routes(彈出路由)
路由不一定要遮擋整個屏幕
4.4 自定義路由
創建自己的一個窗口z組件庫路由類(如 PopupRoute,ModalRoute 或 PageRoute)的子類
可以做什么:
- 動畫
- 路徑的動畫
- 路徑的模態屏障的顏色
- 行為以及路徑的其他各個特性
Navigator.push(context, PageRouteBuilder(
opaque: false, //這個屬性不會遮擋屏幕
pageBuilder: (BuildContext context, _, __) {return Center(child: Text('My PageRoute'));},
transitionsBuilder: (___, Animation<double> animation, ____, Widget child) {
return FadeTransition(
opacity: animation,
child: RotationTransition(
turns: Tween<double>(begin: 0.5, end: 1.0).animate(animation),
child: child,),
);}));
4.5 嵌套路由
一個應用程序可以使用多個路由導航器。將一個導航器嵌套在另一個導航器下方可用于創建“內部旅程”
4.6 數據傳遞和數據返回(頁面間的通信)
1. 數據傳遞
Navigator.push(context, new MaterialPageRoute(builder: (BuildContext context) => new mainPage(params)));
- 在需要接收參數的頁面進行參數定義
- 將參數添加到構造函數中
- 使用MaterialPageRoute并在頁面中傳入參數即可
2.數據返回
2.1 Navigator.of(context).pop('這是頁面5返回的參數'); 在pop中寫上返回的的值,這時候在上方的then中即可得到返回的數據。
2.2
方法一:
String userName = "yinll";
Navigator.push( context, new MaterialPageRoute(
builder: (BuildContext context) =>
new Screen5(userName)))
.then(
(data){ result =data; print(result);
});
方法二:
onTap: () async {
String result = await Navigator.push( context, new MaterialPageRoute(
builder: (context) => new ContentScreen(articles[index]), ), );
if (result != null) {
Scaffold.of(context).showSnackBar(
new SnackBar( content: new Text("$result"), duration: const Duration(seconds: 1), ), );
}}
最佳實踐(實用):
認識路由,一個輕量級的路由管理本質是頁面標識(頁面路徑)與頁面實例的映射
傳統的做法弊端
每個映射的維護影響全局映射配置的穩定性,每次維護映射管理時需要腦補所有的邏輯分支.
無法做到頁面的統一抽象,頁面的構造器和構造邏輯被開發者自定義.
映射配置無法與頁面聯動,把頁面級的配置進行中心化的維護,導致維護責任人缺失.
最佳實踐:路由注解方案(這里是一位阿里同學給出的方案)
annotation_route
-
注解方案設計圖
image.png
參考鏈接:
[https://medium.com/flutter-community/flutter-push-pop-push-1bb718b13c31](https://medium.com/flutter-community/flutter-push-pop-push-1bb718b13c31)
[https://juejin.im/post/5be2d6546fb9a049be5cf6d5#heading-0](https://juejin.im/post/5be2d6546fb9a049be5cf6d5#heading-0)
[https://juejin.im/post/5bbaf7bf5188255c8d0fe309#heading-9](https://juejin.im/post/5bbaf7bf5188255c8d0fe309#heading-9)
[https://blog.csdn.net/mayness/article/details/85762966](https://blog.csdn.net/mayness/article/details/85762966)