【Flutter 實戰】路由堆疊詳解
阿新 • • 發佈:2020-09-16
![](https://img2020.cnblogs.com/other/467322/202009/467322-20200916073451063-89853048.png)
> **老孟導讀**:Flutter中路由是非常重要的部分,任何一個應用程式都離不開路由管理,此文講解路由相關方法的使用和**路由堆疊**的變化。
Flutter 路由管理中有兩個非常重要的概念:
- **Route**:路由是應用程式**頁面**的抽象,對應 Android 中 Activity 和 iOS 中的 ViewController,由 Navigator 管理。
- **Navigator**:Navigator 是一個元件,管理和維護一個基於**堆疊**的歷史記錄,通過 push 和 pop 進行頁面的跳轉。
#### push 和 pop
假設現在有2個頁面 A 和 B,A中有一個按鈕,點選跳轉到 B 頁面,A 頁面程式碼:
```dart
class APage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
child: RaisedButton(
child: Text('A 頁面'),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return BPage();
}));
},
),
);
}
}
```
B 頁面程式碼:
```dart
class BPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
alignment: Alignment.center,
child: RaisedButton(
child: Text('B 頁面'),
onPressed: () {
},
),
),
);
}
}
```
![](https://img2020.cnblogs.com/other/467322/202009/467322-20200916073451506-810717733.gif)
當應用程式位於A頁面時,**路由堆疊**中只有A,點選按鈕跳轉到B頁面,路由堆疊中有 B 和 A,且 B 處於棧頂。
![](https://img2020.cnblogs.com/other/467322/202009/467322-20200916073451685-2025256525.png)
點選 B 頁面的按鈕返回到 A 頁面,修改 B 頁面按鈕點選事件:
```dart
RaisedButton(
child: Text('B 頁面'),
onPressed: () {
Navigator.of(context).pop();
},
)
```
路由堆疊的變化:
![](https://img2020.cnblogs.com/other/467322/202009/467322-20200916073451872-1533537610.png)
上面案例的效果是從 B 頁面跳轉到 A 頁面,那是否也可以使用 push 方法?修改 B 頁面按鈕點選事件:
```dart
RaisedButton(
child: Text('B 頁面'),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return APage();
}));
},
)
```
從效果上看也可以跳轉到 A 頁面,路由堆疊:
![](https://img2020.cnblogs.com/other/467322/202009/467322-20200916073452074-57038397.png)
**那是否可以使用 push 代替 pop 呢?** 答案肯定是不可以的,
1. 試想如下場景,進入購物App,展示購物列表,點選其中一個進入商品詳細頁面,使用 push 再次進入購物列表,然後在進入商品詳細頁面...,如此反覆,路由堆疊中將會存放大量的購物列表和商品詳細頁面的路由,點選返回按鈕,會將反覆顯示購物列表和商品詳細頁面。
2. 頁面切換時路由動畫 push 和 pop 是不同。
#### maybePop 和 canPop
上面案例如果點選 A 頁面按鈕直接呼叫 pop 會如何?
```dart
RaisedButton(
child: Text('A 頁面'),
onPressed: () {
Navigator.of(context).pop();
},
)
```
在 A 頁面時路由堆疊中只有 A,呼叫 pop 後,路由堆疊變化:
![](https://img2020.cnblogs.com/other/467322/202009/467322-20200916073452208-1992480782.png)
此時路由堆疊為空,沒有可顯示的頁面,應用程式將會退出或者黑屏,好的使用者體驗不應如此,此時可以使用 maybePop,maybePop 只在路由堆疊有可彈出路由時才會彈出路由。
上面的案例在 A 頁面執行maybePop:
```dart
RaisedButton(
child: Text('A 頁面'),
onPressed: () {
Navigator.of(context).maybePop();
},
)
```
點選後不會出現彈出路由,因為當前路由堆疊中只有 A,在 B頁面執行maybePop,將會返回到 A 頁面。
也可以通過 canPop 判斷當前是否可以 pop:
```dart
RaisedButton(
child: Text('B 頁面'),
onPressed: () {
if(Navigator.of(context).canPop()){
Navigator.of(context).pop();
}
},
)
```
#### pushNamed
pushNamed 是命名路由的方式,需要在 MaterialApp 中配置路由名稱:
```dart
MaterialApp(
title: 'Flutter Demo',
routes: