Wiki_Flutter_Navigation - inoueshinichi/Wiki_Flutter GitHub Wiki
- 2つの方法(version)がある.
- Navigator ver1
- Navigator ver2 (> Flutter 3.16.x)
- Navigator ver1のNamed Routesは, 非推奨 (> Flutter 3.16.x)
- Android/iOS用の戻るボタンが自動で付与される.
- 単純な画面遷移: Navigator 1.0
- 複雑な画面遷移: Navigator 2.0
- Navigatorウィジェット: スタック管理
- Routeウィジェット: スタックの中身
- Stackに保存されるのは, Routeクラスとその派生クラス
- Routeクラスは画面を抽象化したもの.
- Routeは自分でクラスを作成可能だが, ほとんどのシーンでMaterialPageRouteクラスを利用すれば良い.
- StackにRoute投入してをFILOで管理
|. |. | |
|. | → |. | →
| Route1 |. | Route1 |
---------- ----------
- 指定画面への遷移と状態の転送
- push(): static Future push(BuildContext context, Route route)
- pop()で元のルートに戻る
- pop()は, 画面遷移時に変数値の受け渡しがない限り記述しなくて良い(自動でFlutterが行ってくれる)
### push
# 記述パターン1
var ret = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return NextTargetPage(props_that_you_want_to_pass);
},
fullscreenDialog: true or false,
),
);
# 記述パターン2
var ret = await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) {
return NextTargetPage(props_that_you_want_to_pass);
},
fullscreenDialog: true or false,
),
);
### pop
# 記述パターン1
Navigator.pop<String>(context, "戻り値");
# 記述パターン2
Navigator.of(context).pop<String>("戻り値");
- 非推奨 (Flutter > 3.x)
- 各画面にURIと同じ記法のパスをつけて管理する.
- ルーティング定義は, MaterialAppの1カ所で行う.
- データを渡す方法は, 1種類.
- データを受け取る方法は, 2種類.
-
- ModalRouteクラスを使う方法
-
- onGenerateRouteプロパティ + コンストラクタ引数
e.g.
## MaterialApp
void main() {
runApp(
MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => FirstPage(),
'/second': (context) => SecondPage(),
'/second_with_args': (context) => SecondWithArgPage(),
},
),
);
}
// もしくはGoRouterを使う.
// GoRouterは, PageStackではなく, PageStackそのものの入れ替え
runApp(
MaterialApp.router(
routerConfig: _router,
),
);
final _router = GoRouter(
routes: [
// StackがFirstPageのみ
GoRoute(
path: "/",
builder: (context, state) => FirstPage(),
),
// StackがSecondPageのみ
GoRoute(
path: "/second",
builder: (context, state) => SecondPage(state),
),
// GoRouteを入れ子構造にすると, go(PageStackの入れ替え)がpush(通常のStack)になる
// StackがFourthPageとThirdPageのStackになる
GoRoute(
path: "/third",
builder: (context, state) => ThirdPage(state),
routes: [
GoRoute(
path: "/forth",
builder: (context, state) => FourthPage(state),
),
],
],
],
);
var ret = await Navigator.pushNamed(context, "/second"); var ret = await Navigator.pushNamed( context, "/second_with_args", arguments: "This is message from src to dst", );
var ret = await Navigator.of(context).pushNamed("/second"); var ret = await Navigator.of(context).pushNamed( "/second_with_args", arguments: "This is message from src to dst", );
var passed_args = ModalRoute.of(context).settings.arguments;
// App Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), initialRoute: '/', routes: { '/': (context) => FirstPage(), }, onGenerateRoute: (settings) { if (settings.name == '/second_with_args') { var args_that_you_want_to_pass = settings.arguments; return MaterialPageRoute( builder: (context) { return SecondPage(args_that_you_want_to_pass); }, ); } return null; }, ); // MaterialApp }
## Navigatorクラスのその他のメソッド
### maybePop()メソッド
+ ルートのスタックが残り1つの場合に役立つメソッド.
+ 残り1つになるまではpopする. 最後の1つの場合は,何もしない.
Navigator.maybePop(context);
Navigator.of(context).maybePop();
### canPop()メソッド
+ ルートのスタックが残り1つの場合に警告を出したい場合に使える.
if (!Navigator.canPop(context)) { // TODO 警告表示など } else { Navigator.pop(context); }
if (!Navigator.of(context).canPop()) { // TODO 警告など } else { Navigator.of(context).pop(); }
### pushReplacement() / pushReplacementNamed()
+ FirstPage -> SecondPage -> ThirdPage と画面遷移するパターンを考える.
+ 「SecondPage -> ThirdPage」の画面遷移時に, pushReplacement()またはpushReplacementNamed()を使用した場合, pop()時にFirstPageに1つ跨ぎで画面遷移が戻る.
+ 画面遷移のルーティングが, 「FirstPage -> SecondPage -> ThirdPage」から「FirstPage -> ThirdPage」に置き換わる.
### popAndPushNamed()
+ FirstPage -> SecondPage -> ThirdPage と画面遷移するパターンを考える.
+ 「FirstPage -> SecondPage -> ThirdPage」とThirdPageに遷移後に, `Navigator.popAndPushNamed(context, '/');`とする.
+ UIスタックが「FirstPage -> SecondPage -> FirstPage」となる. (ThirdPageがUIスタックから消える)
### pushAndRemoveUntil() / pushNamedAndRemoveUntil()
+ FirstPage -> SecondPage -> ThirdPage と画面遷移するパターンを考える.
+ 「FirstPage -> SecondPage -> ThirdPage」とThirdPageに遷移後に, pushAndRemoveUntil()またはpushNamedAndRemoveUntil()を呼び出す.
Navigator.pushNamedAndRemoveUntil( context, '/', /RoutePredicate(スタックの削除条件を指定)/(Route route) => false, );
Navigator.of(context).pushNamedAndRemoveUntil( '/', (Route route) => false, );
+ 現在のページ(ThirdPage)から指定ページ(FirstPage)までの経路である「SecondPage -> ThirdPage」が消えて, UIスタックがFirstPageだけになる
+ 第3引数にはRoutePredicateクロージャを指定する.
+ このクロージャーの戻り値は, bool型で削除しない条件を指定する. (今回の場合, 必ずfalseを返しているので全部消える)
+ 第3引数で指定したルートまでpopして, 第2引数のルートに遷移する.
#### 例1
1. UIスタック: FirstPage -> SecondPage -> ThirdPage -> FourthPage と遷移する.
2. FourthPageで`Navigator.pushNamedAndRemoveUntil(context, '/third', ModalRoute.withName('/'));`を実行する.
3. UIスタックが 「FirstPage -> ThirdPage」になる. (FourthPageからThirdPageに遷移し, ThirdPageより親側の画面の中で, 第3引数でtrueより根に近い画面達が残る.)
#### 例2
1. UIスタック: FirstPage -> SecondPage -> ThirdPage -> FourthPage と遷移する.
2. FourthPageで`Navigator.pushNamedAndRemoveUntil(context, '/third', ModalRoute.withName('/second'));`を実行する.
3. UIスタックが 「FirstPage -> SecondPage -> ThirdPage」になる.
#### 例3
1. UIスタック: FirstPage -> SecondPage -> ThirdPage -> FourthPage と遷移する.å
2. FourthPageで`Navigator.pushNamedAndRemoveUntil(context, '/second', ModalRoute.withName('/'));`を実行する.
3. UIスタックが 「FirstPage -> SecondPage」になる.
### popUntil()
1. UIスタック: FirstPage -> SecondPage -> ThirdPage -> FourthPage と遷移する.
2. FourthPageで`Navigator.popUntil(context, ModalRoute.withName('/second'));`を実行する.
3. UIスタックが 「FirstPage -> SecondPage」になる.
## Routeクラス
### 継承関係
+ Route <- PageRoute <- MaterialPageRoute