LoginSignup
73
38

More than 3 years have passed since last update.

[Flutter] Modal bottom sheet内でPush, Popの画面遷移を実現する

Last updated at Posted at 2020-08-30

FlutterでBottom sheet内で画面遷移を実装しようとすると意外と手こずります。

showModalBottomSheetして、Bottom sheet内でNavigator.pushなどしてもpush先の詳細画面がモーダル内で表示されないためです。

before.gif

モーダル内で画面遷移を実現する

モーダル内で画面遷移を実現するポイントは2点です。

  1. Navigatorをネストさせる
  2. 画面を閉じるときはroot側のNavigatorを参照する

1. Navigatorをネストさせる

通常はMaterialAppが保持するNavigatorが、RootのNavigatorとして機能しています。それに加えモーダル用の自前Navigatorを作成することで、モーダル内の画面遷移が実現できます。

具体的なコードは下記です。
Navigatorでモーダルのページを包んで、onGenerateRouteでルートを定義します。

Navigatorクラスの "Nesting Navigators"の章を参照

child: RaisedButton(
  color: Colors.blue,
  textColor: Colors.white,
  onPressed: () => showModalBottomSheet(
    context: context,
    // 自前でモーダル用Navigatorを作成
    builder: (context) => Navigator(
      onGenerateRoute: (context) => MaterialPageRoute<ModalPage>(
        builder: (context) => ModalPage(),
      ),
    ),
  ),
  child: Text('Show modal'),
),

2. 画面を閉じるときはroot側のNavigatorを参照する

1.の対応をするとモーダル内での画面遷移はうまくいきますが、Xボタンなどでモーダルを閉じるときに下のような挙動になり、うまく閉じません

after1.gif

これは1.の対応をした際、Routeがネストされた構造になっているからです。ネストした子のRoute側でpopするのでモーダルが残ったままになります

これは、Navigator.of(context, rootNavigator: true) でRootのNavigatorを指定することで解決できます

return Scaffold(
  appBar: AppBar(
    leading: IconButton(
        // 閉じるときはネストしているModal内のRouteではなく、root側のNavigatorを指定する必要がある
        onPressed: () => Navigator.of(context, rootNavigator: true).pop(),
        icon: Icon(Icons.close)),
    title: Text('Modal'),
  ),

完成 :tada:

complete.gif

おまけ

触って動かせるDemoをDartPadに置いておいたので、ご活用ください
https://dartpad.dartlang.org/65afaedbe5016c4d5c4f20549c575e55

73
38
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
73
38