Flutterで画面遷移を実装する

昨日の続き。BottomNavigationBarの画面遷移を実装します。

といいつついきなりBottomNavigationBarはさておいて、画面遷移の方法はどうやら大きくわけて3つあるようです。

  1. Navigatorクラスを使ってpush/pop
  2. ウィジェットの切り替えを行う
  3. PageControllerを実装してがんばる

みっつめの方法はあまりメジャーじゃないっぽい?(お作法がまだよくわからない)ので、ひとつめとふたつめの方法を見ていきます。

Navigatorクラスを使う

ひとつめ、Navigatorクラスを使うパターン。
main.dartmain()で呼び出しているStatelessWidgetで、いままではこんな感じでホームとなるStatefulWidgetを呼び出していました。

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'MyApp',
      home: MyHomePage(),
    );
  }
}

このhomeを消して、ここでrouteを設定します。
routeをウィジェットの中に直書きするのは少し違和感。
ウィジェットをスタックしていくから仕方ないのでしょうか🤔

ともあれこんな風に書き換えます。

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'MyApp',
      initialRoute: '/',
      routes: {
        '/': (context) => MyHomePage(),
        '/awesomePage': (context) => AwesomePage(),
      },
    );
  }
}

routesプロパティの中に呼び出し名(route)と呼び出すStatefulWidget名をセットで記載します。

initialRouteがアプリ起動時に呼び出されるroute。通常はスプラッシュ画面を呼び出すところですね。
今回はMyHomePageを起動時に呼び出したかったので、initialRouteである'/'MyHomePageを紐づけました。

RaisedButtonをタップした時なんかに、ここでつけた名前をつかって画面遷移ができます。

RaisedButton(
  onPressed: () => {Navigator.pushNamed(context, '/awesomePage')},
),

ウィジェットの切り替えを行う

昨日書いたBottomNavigationBarに画面遷移を実装したものがこれ。

class _MyHomePageState extends State<MyHomePage> {
  int _currentIndex = 0;

  @override
  Widget build(BuildContext context){
    return Scaffold(
      appBar: AppBar(
        title: Text('MyHomePage'),
      ),
      body: _currentIndex == 0 ? Text('Home') : Text('Settings'),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: 0,
        onTap: (int index) {
          setState((){
            this._currentIndex = index;
          });
        },
        items: [
          new BottomNavigationBarItem(
            icon: new Icon(Icons.home),
            title: new Text("Home")
          ),
          new BottomNavigationBarItem(
            icon: new Icon(Icons.settings),
            title: new Text("Setting")
          ),
        ],
      ),
    );
  }
}

BottomNavigationBarをtapするとMyHomePageStatecurrentIndexを変更、currentIndexの変更でbodyを書き換えています。
ここでは単純にTextウィジェットを表示しているだけですが、ContainerCustomScrollViewなどを返します。

とても単純なのですが、これだと画面から非表示になったウィジェットは解放されるのでStatefulWidgetを使う場合には(Stateが解放されて)意図した動きにならない。
ので、Stackウィジェットを使って画面を持ちつつ、Offstageで表示切り替えをして、MaterialAppNavigatorを使う、というのがちゃんとした方法のようです。
こちらで詳しく解説されています

以上、画面遷移の方法でした!