---
title: 'Flutter 導航&路由'
disqus: kyleAlien
---
Flutter 導航&路由
===
## Overview of Content
**路由(Route)管理就是在 Flutter 移動開發中通常是指頁面的跳轉**,如同我們在開發 Android 時不同的 Module 跳轉就需要一個路由器,而 Flutter 的頁面跳轉也有自己的路由器風格
:::success
* 如果喜歡讀更好看一點的網頁版本,可以到我新做的網站 [**DevTech Ascendancy Hub**](https://devtechascendancy.com/)
本篇文章對應的是 [**深入解析 Flutter Navigator:常見錯誤、解決方法與路由跳轉技巧、動畫**](https://devtechascendancy.com/flutter-navigator-guide_routing-animation/)
:::
:::info
以下使用的 Flutter 版本為 `3.22.2`
:::
[TOC]
## 認識 Navigator
Fluttter 使用 Navigator 類來跳轉頁面
### Navigator 錯誤的使用方式
* **以下的範例是一個錯誤的範例**,接下來我們會分析這個錯誤,並將它導向正確
> 以下是程式碼目的是 Page1 頁面,跳轉到 Page2 頁面
1. Page1 頁面:在這個頁面中做個簡單的 Btn 來跳轉到 Page2 頁面
```dart=
class Page1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text("主頁面")),
body: RaisedButton(
child: Text("跳轉 Page2"),
onPressed: () {
debugPrint("點擊跳轉按鈕");
/// Navigator 也是 Widget
// 跳轉到 Page2 頁面
Navigator.of(context).push(
MaterialPageRoute( // Route 是抽象類
builder: (BuildContext context) {
return Page2();
}
)
);
},
)
),
);
}
}
```
2. Page2 頁面
```dart=
class Page2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text("頁面")),
body: Text("頁面 2"),
),
);
}
}
```
**--出錯結果--**
:::warning
錯誤:`Navigator operation requested with a context that does not include a Navigator.`(使用不包含導航器的上下文請求導航器操作)
:::
> 
### Navigator 錯誤分析
* 接下來分析 Navigator 錯誤,帶到 `Navigator#of` 方法,就可以發現我們剛剛在外部看得完全一樣的錯誤訊息,並且還可以發現以下事情
1. 在進入 `Navigator#of` 方法時,它會先獲取 `NavigatorState` 物件,而獲取的方法有三種…
* 透過 BuildContext#`state` 獲取
* 透過 BuildContext#`findRootAncestorStateOfType` 獲取
* 透過 BuildContext#`findAncestorStateOfType` 獲取(等等往下分析)
> 等等主要分析 `findAncestorStateOfType` 函數,操作就像是再呼叫 BuildContext 的父類別,並去尋找其中的 `NavigatorState` 物件
```dart=
// navigator.dart 的源碼
static NavigatorState of(
BuildContext context, {
bool rootNavigator = false,
}) {
// Handles the case where the input context is a navigator element.
NavigatorState? navigator;
if (context is StatefulElement && context.state is NavigatorState) {
navigator = context.state as NavigatorState;
}
if (rootNavigator) {
navigator = context.findRootAncestorStateOfType<NavigatorState>() ?? navigator;
} else {
navigator = navigator ?? context.findAncestorStateOfType<NavigatorState>();
}
... 省略
}
```
2. 透過 `assert()` 斷言來確保有取得 `NavigatorState` 物件
```dart=
// navigator.dart 的源碼
static NavigatorState of(
BuildContext context, {
bool rootNavigator = false,
}) {
... 省略
assert(() {
if (navigator == null) {
throw FlutterError(
'Navigator operation requested with a context that does not include a Navigator.\n'
'The context used to push or pop routes from the Navigator must be that of a '
'widget that is a descendant of a Navigator widget.',
);
}
return true;
}());
return navigator!;
}
```
3. 進入 BuildContext#`findAncestorStateOfType` 方法,我們可以發現以下事情
* BuildContext#`findAncestorStateOfType` 方法的實作類是 `Element` 類
```mermaid
classDiagram
BuildContext <|-- Element: 繼承
BuildContext: State state
BuildContext: +(T extends State) findAncestorStateOfType()
State <.. BuildContext: 依賴、關聯
```
* 並且 Element 內部有一個自身類型的成員 `_parent`,而 `findAncestorStateOfType` 方法則透過「鏈結」的方式不斷去尋找其父類別中的哪個類別屬於 T 屬性(也就是尋找 `NavigatorState` 物件)
:::info
* 這種設計模式就是 [Chain 責任鏈模式](https://devtechascendancy.com/object-oriented_design_chain_framework/),有興趣的人可以點擊連結了解這種設計模式
```mermaid
classDiagram
BuildContext <|-- Element: 繼承
BuildContext: State state
BuildContext: +(T extends State) findAncestorStateOfType()
State <.. BuildContext: 依賴、關聯
Element <|-- Element
Element: -Element _parent
```
:::
```dart=
// 可以發現該方法為 abstract 抽象方法 (framework.dart 中的 BuildContext)
T findAncestorStateOfType<T extends State>();
// --------------------------------------------------------------------
// 以下是該方法的實做 (framework.dart 中的 Element)
abstract class Element extends DiagnosticableTree implements BuildContext {
Element? _parent;
...
@override
T findAncestorStateOfType<T extends State<StatefulWidget>>() {
assert(_debugCheckStateIsActiveForAncestorLookup());
// "1. " 獲取父節點
Element ancestor = _parent;
while (ancestor != null) {
if (ancestor is StatefulElement && ancestor.state is T)
break;
// 2. 不斷往上找
ancestor = ancestor._parent;
}
final StatefulElement statefulAncestor = ancestor as StatefulElement;
return statefulAncestor?.state as T;
}
...
}
```
:::success
* **Context & Elements 關係是什麼**?
1. Elements 這個類是實現了 BuildContext 類
> 可以發現 BuildContext 的抽象由 Element 實做… 也就是實際顯示的 View (**Widget 最終會創建出 Element 元件**)
> 
2. 在我們定義的 StatefulWidget、StatelessWidget 中所拿到的 BuildContext 就是 Elements 的 BuildContext
> 
3. StatefulWidget、StatelessWidget 中的 context 其實就是當前頁面
> 
:::
:::info
* 最終可以發現 Navigator 跳轉的關鍵在於 BuildContext 上下文的尋找到 `state` 成員為 `NavigatorState` 物件才可以正常跳轉
:::
* 使用 Debug 模式來觀察 BuildContext#`_parent` 是哪個類,可以發現 Page1 它的父親是 RenderView (Root View),它類似於 Android 布局中的 Decor View(畫面的根佈局)
> 
而 RenderView(Root View)的上一層就沒有其他的 Element,導致返回為 null,這也是為何無法正常跳轉的原因,因為在所有父類中根本找不到有哪個類是 `NavigatorState` 物件
> 
:::warning
* 嘗試改為 StatelessWidget 修改為 StatefulWidget 有用嗎?
嘗試改為 StatefulWidget,會發現不管用,因為**不管是 StatelessWidget / StatefulWidget 都是相同的 RootView**
```dart=
// 該程式輸出結果同樣錯誤,無法跳轉
void main() => runApp(FixFul());
class FixFul extends StatefulWidget {
@override
FixFulState createState() => FixFulState();
}
class FixFulState extends State<FixFul> {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text("主頁面")),
body: RaisedButton(
child: Text("跳轉 Page2"),
onPressed: () {
debugPrint("點擊跳轉按鈕");
/// Navigator 也是 Widget
Navigator.of(context).push(
MaterialPageRoute( // Route 是抽象類
builder: (BuildContext context) {
return Page2();
}
)
);
},
)
),
);
}
}
```
:::
### Navigator 跳轉失敗的解決方法:自訂 Navigator、層級分離
* 透過上面 Navigator 跳轉失敗的原因,我們就可以知道,是因為父類中沒有任何一個類有實作 `NavigatorState` 類,這才導致跳轉失敗,而解決這個問題的方法有以下幾中
1. 自己定義 Navigator:自己創建一個 `GlobalKey<NavigatorState>` 物件,並設定給 MaterialApp#`navigatorKey` 成員
```dart=
import 'package:flutter/material.dart';
void main() => runApp(Page1());
class Page1 extends StatelessWidget {
/// 自定義導航 Key
final GlobalKey<NavigatorState> navigatorKey = GlobalKey();
@override
Widget build(BuildContext context) {
return MaterialApp(
/// 賦予 MaterialApp Key
navigatorKey: navigatorKey,
home: Scaffold(
appBar: AppBar(title: Text("主頁面")),
body: RaisedButton(
child: Text("跳轉 Page2"),
onPressed: () {
debugPrint("navigatorKey type: ${navigatorKey.currentWidget.runtimeType.toString()}");
navigatorKey.currentState.push(MaterialPageRoute(
builder: (BuildContext context) {
return Page2();
}
));
},
)
)
);
}
}
class Page2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text("頁面")),
body: RaisedButton(
child: Text("返回頁面"),
onPressed: (){
Navigator.pop(context); // 回到上個頁面
},
),
),
);
}
}
```
2. **層級進行分離**:透過在 MaterialApp 與 Page1 中間夾帶另一個 Widget 的方式進行跳轉,以下舉兩個使用層級分離的方案
* 透過 `Builder` 來包裝頁面:透過 Builder 中的 `builder` 成員給予的 BuildContext 來跳轉頁面
```dart=
import 'package:flutter/material.dart';
void main() => runApp(Page1());
class Page1 extends StatelessWidget {
Widget builder(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("主頁面")),
body: RaisedButton(
child: Text("跳轉 Page2"),
onPressed: () {
debugPrint("點擊跳轉按鈕");
/// 此時修改傳入的 context 就是 Builder,Builder 的 Parent 就是 MaterialApp
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return Page2();
}
)
);
},
)
);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
// Builder 是一個基礎 Widget
home: Builder(
builder: builder,
)
);
}
}
class Page2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text("頁面")),
body: Text("頁面 2"),
),
);
}
}
```
**--實做結果--**
> 
:::info
* 而 Builder 並非一定要放置在範例程式中的位置,**觀念是 Context 上下文的尋找,++只要放置在 MaterialApp 的下層即可++**
:::
* **自訂中間層**:Builder 是個 Widget,而我們也可以自訂一個 Widget
```dart=
import 'package:flutter/material.dart';
void main() => runApp(Page1());
class CoverPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("主頁面")),
body: RaisedButton(
child: Text("跳轉 Page2"),
onPressed: () {
debugPrint("點擊跳轉按鈕");
/// 此時傳入的 context 就是 CoverPage's context,其上一級就是 Material App
Navigator.of(context).push(
MaterialPageRoute(
builder: (BuildContext context) {
return Page2();
}
)
);
},
)
);
}
}
class Page1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: CoverPage()
);
}
}
class Page2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text("頁面")),
body: Text("頁面 2"),
),
);
}
}
```
**--實做結果--**
> 
### 層級分離概念
* 接著我們也會會好奇為什麼只要套用在自己的 Widget 與 MaterialApp 中間夾帶一層中間層 Widget 就可以就可以正常跳轉?
在最上面我們失敗的實驗中可以看到 Navigator.of 的操作是往父類 Widget 搜尋 Router(它預設不會使用搜尋創建的 Router),而 MaterialApp 的父類 Widget 就是根佈局
> 根佈局(RenderView)不會有 Router 可用
```mermaid
graph LR
subgraph RenderView
render_view
subgraph MaterialApp
Navigator.of
Router
context
end
end
Navigator.of -.-> |往上層找| context
context -.-> |找不到 Router| render_view
```
* 使用層級分離的技巧後,Navigator.of 的上下文就會在層級內部,這就導致 Navigator.of 可以找到 MaterialApp 的 Router
```mermaid
graph LR
subgraph RenderView
subgraph MaterialApp
Router
subgraph 層級 Widget
Navigator.of
context
end
end
render_view
end
Navigator.of -.-> |往上層找| context
context -.-> |找到 Router| Router
```
### 深究 MaterialApp 創建的 NavigatorState
* MaterialApp 本身其實就在創建時附帶有路由器(`NavigatorState`)的功能,而這裡我們就來挖掘一下 MaterialApp 創建 NavigatorState 的時機點
MaterialApp 是一個 StatefulWidget,所以我們從它創建 State 的 `createState` 函數開始
:::success
* 為什麼從 `createState` 函數開始?
因為這個 `createState` 函數創建出來的 State 會被賦予到 Element#`_state` 中,最終會影響到 BuildContext#`state`,也就會影響是否可以正確地找到 `NavigatorState` 物件
:::
1. MaterialApp#`createState` 函數會創建 `_MaterialAppState` 物件
```dart=
// material/app.dart
@override
State<MaterialApp> createState() => _MaterialAppState();
```
> 
2. _MaterialAppState#`build` 函數會創建 `WidgetsApp` 物件
```dart=
// material/app.dart
@override
Widget build(BuildContext context) {
Widget result = _buildWidgetApp(context);
... 省略部分
}
Widget _buildWidgetApp(BuildContext context) {
... 省略部分
return WidgetsApp(...);
}
```
3. 而 WidgetsApp 也是 `StatefulWidget`,所以同樣從 `createState` 函數開始看… 可以看到它創建了 `_WidgetsAppState` 物件
```dart=
// widgets/app.dart
@override
State<WidgetsApp> createState() => _WidgetsAppState();
```
幾著繼續看 _WidgetsAppState#`build` 方法,可以看到在沒有代理的情況下,它會創建一個 `Navigator` 物件作為 Widget
```dart=
// widgets/app.dart
@override
Widget build(BuildContext context) {
Widget? routing;
if (_usesRouterWithDelegates) {
... 省略
} else if (_usesNavigator) {
assert(_navigator != null);
routing = FocusScope(
debugLabel: 'Navigator Scope',
autofocus: true,
child: Navigator( // 創建 Navigator 類
... 省略
),
);
}
```
4. 最後,我們可以在 Navigator 類中的 `createState` 函數中,看到 NavigatorState 被創建出來!!
```dart=
// navigator.dart
@override
NavigatorState createState() => NavigatorState();
```
> 
## 命名路由
另外一種不透過層級分離的技巧就可以跳轉頁面的方式,就是透過設定「命名路由」來跳轉
### 命名路由使用範例
* 路由針對每個頁面取名,然後**通過頁面名子傳遞給路由器就可以直接開啟**,跳轉頁面使用 Navigator#pushName 方法
範例如下:
```dart=
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Flutter_Router_Demo",
/// routes 原型:final Map<String, WidgetBuilder>
/// WidgetBuilder 原型:typedef WidgetBuilder = Widget Function(BuildContext context);
routes: {
"/": (BuildContext context) => MainPage(),
"Page1": (BuildContext context) => Page1(),
},
);
}
}
class MainPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Build")),
body: Column(
children: <Widget>[
Text("主頁面"),
RaisedButton(
child: Text("跳轉"),
onPressed: () {
debugPrint("跳轉頁面");
Navigator.pushNamed(context, "Page1");
},
)
],
),
);
}
}
class Page1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Build")),
body: Column(
children: <Widget>[
Text("頁面二"),
RaisedButton(
child: Text("返回"),
onPressed: () {
debugPrint("返回頁面");
Navigator.pop(context);
//Navigator.pushNamed(context, "/");
},
)
],
),
);
}
}
```
**--實做結果--**
> 跳轉成功
>
> 
:::warning
* 命名路由中 `/`是一種特殊的名子,它代表了「**主頁面**」,有了 `/` 就不能使用 Material 的 home 屬性,否則就會報錯
> 
:::
## Navigator 跳轉結果
在 Android `StartActivityForResult` 可以查看跳轉的結果,而 Flutter 則更加的方便,在轉跳的 `Navigator#push` or `Navigator#pushName` 方法返回的是一個 Future 物件,配合使用 `async`、`await` 就可以堵塞並獲取結果
> 
### 取得 Navigator 跳轉結果:範例一
* 取得 Navigator 跳轉結果範例如下
1. 設定基礎的命名路由
```dart=
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Flutter_Router_Demo",
/// routes 原型:final Map<String, WidgetBuilder>
/// WidgetBuilder 原型:typedef WidgetBuilder = Widget Function(BuildContext context);
routes: {
"/": (BuildContext context) => MainPage(),
"Page1": (BuildContext context) => Page1(),
},
home: MainPage(),
);
}
}
```
2. 設定跳轉頁面,並使用 `async`、`await` 關鍵字來等待該頁面返回的結果
```dart=
class MainPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Build")),
body: Column(
children: <Widget>[
Text("主頁面"),
RaisedButton(
child: Text("跳轉"),
/// 若沒有使用 async await 則無法接收轉跳參數
onPressed: () async {
debugPrint("跳轉頁面");
var r = await Navigator.pushNamed(context, "Page1");
debugPrint("Finish: $r");
},
)
],
),
);
}
}
```
3. 頁面在返回時使用 `Navigator.pop`,並設定返回的數據,在返回之後 `MainPage` 就可以取得 `Page1` 返回的數據
```dart=
class Page1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Build")),
body: Column(
children: <Widget>[
Text("頁面二"),
RaisedButton(
child: Text("返回"),
onPressed: () {
debugPrint("返回頁面");
/// 返回參數
Navigator.pop(context, "Page1 Finish");
},
)
],
),
);
}
}
```
**--實做結果--**
> 
### Navigator 返回數據:範例二
* Navigator 返回數據的第二個範例如下
```dart=
import 'package:flutter/material.dart';
void main() => runApp(MyFirstNavigator());
class MyFirstNavigator extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: "Navigator",
home: Scaffold(
appBar: AppBar(
title: const Text("First Page")
),
body: Builder(builder: (context) { // 使用 Builder 的 Context
return RaisedButton(
onPressed: () {
_waitNavigatorData(context);
},
child: Text("Jump to second page."),
);
})
),
);
}
void _waitNavigatorData(BuildContext context) async {
var push = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MySecondNavigator()
)
);
Scaffold.of(context).showSnackBar(
new SnackBar(content: new Text("$push"))
);
}
}
class MySecondNavigator extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: "Navigator",
home: Scaffold(
appBar: AppBar(
title: const Text("First Page")
),
body: Center(
child: RaisedButton(
onPressed: () {
// 回傳數值 泛型 T
Navigator.pop(context, "Hello Navigator");
},
child: Text("Return Msg."),
),
)
),
);
}
}
```
> 
## 路由跳轉動畫
上面我們在 Router 中跳轉頁面是使用 Material 風格的動畫 (也就是 MaterialPageRoute 類)
### 自動路由跳轉動畫
* 如果要自訂動畫 **需要透過 `PageRouteBuilder` Widget 設定**,範例如下:以下動畫效果為「翻頁」第二頁由下至上反滾下來
```dart=
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
home: MainRoute(),
);
}
}
class MainRoute extends StatelessWidget {
Route routeWithAnimation() {
return PageRouteBuilder(
/// 設定動畫時間
transitionDuration: Duration(milliseconds: 1500),
/// 原型如下:
/// typedef RoutePageBuilder = Widget Function(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation);
pageBuilder: (context, animation, secondaryAnimation) {
/// SlideTransition 平移
return SlideTransition(
/// Tween: 補間動畫
position: Tween<Offset>(
/// 上至下的平移
begin: const Offset(0.0, -1.0), // 開始點
end: const Offset(0.0, 0.0), // 結束點
).animate(animation),
/// 目標跳轉界面
child: Page1(),
);
}
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Main Page")),
body: Center (
child: Column(
children: <Widget>[
Text("主頁面"),
RaisedButton(
child: Text("跳轉"),
onPressed: () async {
debugPrint("頁面跳轉");
var r = await Navigator.of(context).push(
// 呼叫 route 動畫
routeWithAnimation()
);
debugPrint("頁面跳轉結束:$r");
},
)
],
),
),
);
}
}
class Page1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Second Page")),
body: Center (
child: Column(
children: <Widget>[
Text("子頁面"),
Builder(
builder: (context) {
return RaisedButton(
child: Text("返回"),
onPressed: () {
Navigator.pop(context, "Hey~ I'm Second Page");
},
);
},
),
],
),
),
);
}
}
```
### 自訂跳轉組合動畫
* 在動畫中的 child 再嵌入動畫,最內層的動畫再呼叫目標頁面; 可依照這個概念在嵌套更多的動畫,範例如下:以下使用「**使用淡入動畫 + 平移動畫**」
```dart=
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
home: MainRoute(),
);
}
}
class MainRoute extends StatelessWidget {
Route myAnimation() {
return PageRouteBuilder(
/// 設定動畫時間
transitionDuration: Duration(milliseconds: 1500),
/// 原型如下:
/// typedef RoutePageBuilder = Widget Function(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation);
pageBuilder: (context, animation, secondaryAnimation) {
/// SlideTransition 平移
return SlideTransition(
/// Tween: 補間動畫
position: Tween<Offset>(
/// 左至右的平移
begin: const Offset(1.0, 0.0), // 開始點
end: const Offset(0.0, 0.0), // 結束點
).animate(animation),
/// 目標跳轉界面
child: new FadeTransition(
opacity: animation,
child: Page1(),
),
);
}
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Main Page")),
body: Center (
child: Column(
children: <Widget>[
Text("主頁面"),
RaisedButton(
child: Text("跳轉"),
onPressed: () async {
debugPrint("頁面跳轉");
var r = await Navigator.of(context).push(
myAnimation()
);
debugPrint("頁面跳轉結束:$r");
},
)
],
),
),
);
}
}
class Page1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Second Page")),
body: Center (
child: Column(
children: <Widget>[
Text("子頁面"),
Builder(
builder: (context) {
return RaisedButton(
child: Text("返回"),
onPressed: () {
Navigator.pop(context, "Hey~ I'm Second Page");
},
);
},
),
],
),
),
);
}
}
```
## Appendix & FAQ
:::info
:::
###### tags: `Flutter`