Flutter的設(shè)計(jì)貌似對(duì)前端同學(xué)比較友好蔗崎,言歸正傳,先從原理開(kāi)始,然后是具體的case,好侮腹,我們開(kāi)始:
小提示:電腦端閱讀更佳
1. 路由工作原理:
對(duì)于原來(lái)移動(dòng)端開(kāi)發(fā)的同學(xué),多了件事情稻励,管理路由父阻。簡(jiǎn)單講路由的工作原理是通過(guò)路由對(duì)象的進(jìn)出棧來(lái)使用戶從一個(gè)頁(yè)面跳轉(zhuǎn)到另一個(gè)頁(yè)面。
2. 路由是什么望抽?
在Flutter 中理解好路由(Route), 離不開(kāi)另一個(gè)概念導(dǎo)航(Navigator), Flutter中路由管理, 主要依賴的是 Navigator(導(dǎo)航器)類, 這是一個(gè)用于管理一組具有某種進(jìn)出規(guī)則的頁(yè)面的 Widget, 也就是說(shuō)用它我們能夠?qū)崿F(xiàn)各個(gè)頁(yè)面間有規(guī)律的切換, 而這里的規(guī)則便是在其內(nèi)部維護(hù)的一個(gè)“ 路由棧加矛。
3. 路由的種類:
路由分為 組件路由,命名路由煤篙,自定義路由斟览,嵌套路由。
4. 使用方法:
Navigator:導(dǎo)航器,負(fù)責(zé)管理路由
路由名稱命名:路由名稱通常使用路徑結(jié)構(gòu):“/a/b/c”辑奈,主頁(yè)默認(rèn)為 “/”苛茂。
4.1 PUSH 使用
1. pushNamed
Navigator.of(context).pushNamed('routeName');
簡(jiǎn)單的將我們需要進(jìn)入的頁(yè)面push到棧頂已烤,以此來(lái)顯示當(dāng)前頁(yè)面,其參數(shù)是一個(gè)字符串類型,傳入的是頁(yè)面對(duì)應(yīng)的路由名稱 該路由名稱需要在程序主入口中進(jìn)行定義:
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');
指把當(dāng)前頁(yè)面在棧中的位置替換成跳轉(zhuǎn)的頁(yè)面(替換導(dǎo)航器的當(dāng)前路由妓羊,通過(guò)推送路由[routeName])胯究,當(dāng)新的頁(yè)面進(jìn)入后,之前的頁(yè)面將執(zhí)行dispose方法躁绸。
下面為官方說(shuō)明:
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裕循。它應(yīng)該只顯示一次,用戶不應(yīng)該再?gòu)闹髌聊换氐剿茄铡T谶@種情況下费韭,由于我們將要進(jìn)入一個(gè)全新的屏幕, 我們可能想要使用這個(gè)方法來(lái)實(shí)現(xiàn)它的enter animation屬性庭瑰。
3.pushReplacement
特點(diǎn):可以通信星持,頁(yè)面間傳遞參數(shù)
Navigator.pushReplacement( context, MaterialPageRoute(builder: (BuildContext context) => screen4(param)));
4. popAndPushNamed
Navigator.popAndPushNamed(context, 'routeName');
指把當(dāng)前頁(yè)面在棧中的位置替換成跳轉(zhuǎn)的頁(yè)面(替換導(dǎo)航器的當(dāng)前路由,通過(guò)推送路由[routeName])弹灭,當(dāng)新的頁(yè)面進(jìn)入后督暂,之前的頁(yè)面將執(zhí)行dispose方法。
下面為官方說(shuō)明:
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:
例如 在購(gòu)物應(yīng)用中穷吮,有產(chǎn)品列表逻翁,用戶在產(chǎn)品列表中可以通過(guò)篩選,來(lái)進(jìn)一步選擇商品捡鱼,在這個(gè)過(guò)程中八回,用戶點(diǎn)擊篩選按鈕時(shí),會(huì)進(jìn)入篩選條件選擇界面驾诈,當(dāng)用戶點(diǎn)擊 確定篩選按鈕時(shí)缠诅,應(yīng)彈出篩選界面,并使用新的篩選條件進(jìn)入產(chǎn)品列表乍迄。這種情況popAndPushNamed就更合適了管引。
5. pushNamedAndRemoveUntil
Navigator.of(context).pushNamedAndRemoveUntil('routeName', (Route<dynamic> route) => false);
指將制定的頁(yè)面加入到路由中,然后將其他所有的頁(yè)面全部pop, (Route route) => false將確保刪除推送路線之前的所有路線闯两。 這時(shí)候?qū)⒋蜷_(kāi)一個(gè)新的routeName頁(yè)
Case Study:
使用情況:例如 當(dāng)用戶點(diǎn)擊了退出登錄時(shí)褥伴,我們需要進(jìn)入某一個(gè)頁(yè)面(比如點(diǎn)退出登錄后進(jìn)入了登錄頁(yè)),這個(gè)時(shí)候用戶點(diǎn)擊返回時(shí)不應(yīng)該能進(jìn)入任何一個(gè)頁(yè)面漾狼,這種情況就可以使用重慢。
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 會(huì)自動(dòng)進(jìn)行判斷,如果當(dāng)前頁(yè)面pop后逊躁,會(huì)顯示其他頁(yè)面伤锚,不會(huì)出現(xiàn)問(wèn)題,則將執(zhí)行當(dāng)前頁(yè)面的pop操作 否則將不執(zhí)行。
Case Study:
如果我們?cè)诔跏悸酚缮喜⑶矣腥隋e(cuò)誤地試圖彈出這個(gè)唯一頁(yè)面怎么辦屯援? 彈出堆棧中唯一的頁(yè)面將關(guān)閉您的應(yīng)用程序,因?yàn)樗竺嬉呀?jīng)沒(méi)有頁(yè)面了念脯。這顯然是不好的體驗(yàn)狞洋。 這就是 maybePop() 起的作用。
2.canPop
Navigator.of(context).canPop();
canPop 判斷當(dāng)前頁(yè)面能否進(jìn)行pop操作绿店,并返回bool值
3.pop
Navigator.of(context).pop();
直接退出當(dāng)前頁(yè)面
4.3 Popup routes(彈出路由)
路由不一定要遮擋整個(gè)屏幕
4.4 自定義路由
創(chuàng)建自己的一個(gè)窗口z組件庫(kù)路由類(如 PopupRoute吉懊,ModalRoute 或 PageRoute)的子類
可以做什么:
- 動(dòng)畫
- 路徑的動(dòng)畫
- 路徑的模態(tài)屏障的顏色
- 行為以及路徑的其他各個(gè)特性
Navigator.push(context, PageRouteBuilder(
opaque: false, //這個(gè)屬性不會(huì)遮擋屏幕
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 嵌套路由
一個(gè)應(yīng)用程序可以使用多個(gè)路由導(dǎo)航器。將一個(gè)導(dǎo)航器嵌套在另一個(gè)導(dǎo)航器下方可用于創(chuàng)建“內(nèi)部旅程”
4.6 數(shù)據(jù)傳遞和數(shù)據(jù)返回(頁(yè)面間的通信)
1. 數(shù)據(jù)傳遞
Navigator.push(context, new MaterialPageRoute(builder: (BuildContext context) => new mainPage(params)));
- 在需要接收參數(shù)的頁(yè)面進(jìn)行參數(shù)定義
- 將參數(shù)添加到構(gòu)造函數(shù)中
- 使用MaterialPageRoute并在頁(yè)面中傳入?yún)?shù)即可
2.數(shù)據(jù)返回
2.1 Navigator.of(context).pop('這是頁(yè)面5返回的參數(shù)'); 在pop中寫上返回的的值假勿,這時(shí)候在上方的then中即可得到返回的數(shù)據(jù)借嗽。
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), ), );
}}
最佳實(shí)踐(實(shí)用):
認(rèn)識(shí)路由,一個(gè)輕量級(jí)的路由管理本質(zhì)是頁(yè)面標(biāo)識(shí)(頁(yè)面路徑)與頁(yè)面實(shí)例的映射
傳統(tǒng)的做法弊端
每個(gè)映射的維護(hù)影響全局映射配置的穩(wěn)定性转培,每次維護(hù)映射管理時(shí)需要腦補(bǔ)所有的邏輯分支.
無(wú)法做到頁(yè)面的統(tǒng)一抽象恶导,頁(yè)面的構(gòu)造器和構(gòu)造邏輯被開(kāi)發(fā)者自定義.
映射配置無(wú)法與頁(yè)面聯(lián)動(dòng),把頁(yè)面級(jí)的配置進(jìn)行中心化的維護(hù)浸须,導(dǎo)致維護(hù)責(zé)任人缺失.
最佳實(shí)踐:路由注解方案(這里是一位阿里同學(xué)給出的方案)
annotation_route
-
注解方案設(shè)計(jì)圖
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)