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 1.0 に関する画面遷移の仕組み

1. Stack方式

  • Navigatorウィジェット: スタック管理
  • Routeウィジェット: スタックの中身
  • Stackに保存されるのは, Routeクラスとその派生クラス
  • Routeクラスは画面を抽象化したもの.
  • Routeは自分でクラスを作成可能だが, ほとんどのシーンでMaterialPageRouteクラスを利用すれば良い.
  • StackにRoute投入してをFILOで管理
|.       |.  |        |
|.       | → |.       | → 
| Route1 |.  | Route1 |
----------   ----------

Navigator.push()とNavigator.pop()

  • 指定画面への遷移と状態の転送
  • 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>("戻り値");

2. URL方式 (NamedRoutes)

  • 非推奨 (Flutter > 3.x)
  • 各画面にURIと同じ記法のパスをつけて管理する.
  • ルーティング定義は, MaterialAppの1カ所で行う.
  • データを渡す方法は, 1種類.
  • データを受け取る方法は, 2種類.
    1. ModalRouteクラスを使う方法
    1. 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),
        ),
      ],
    ],
  ],
);

pushNamed

記述パターン1

var ret = await Navigator.pushNamed(context, "/second"); var ret = await Navigator.pushNamed( context, "/second_with_args", arguments: "This is message from src to dst", );

記述パターン2

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", );

ModalRouteクラスを使用して引数を受け取る

var passed_args = ModalRoute.of(context).settings.arguments;

onGenerateRouteプロパティ+コンストラクタ引数

// 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つの場合は,何もしない.

1

Navigator.maybePop(context);

2

Navigator.of(context).maybePop();


### canPop()メソッド
+ ルートのスタックが残り1つの場合に警告を出したい場合に使える.

1

if (!Navigator.canPop(context)) { // TODO 警告表示など } else { Navigator.pop(context); }

2

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()を呼び出す.

1

Navigator.pushNamedAndRemoveUntil( context, '/', /RoutePredicate(スタックの削除条件を指定)/(Route route) => false, );

2

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

⚠️ **GitHub.com Fallback** ⚠️