Loading
BLOG 開発者ブログ

2020年3月6日

Flutterで画面遷移させてみた!!

Flutterでは画面遷移ってどう実装すればいいんだろう?
そんな疑問を解消するために3画面構成のアプリケーションを作成してみます。

こんにちは。モバイルソリューショングループのishimaru.rです。
この記事では、Flutterで画面遷移を実装しようと思った時にどういった処理が必要なのかについて記載します。
また、実装するにあたりつまづき時間が掛かってしまったポイントについても記載していますので、
読んでいただいてる方のご参考になればと思います!

完成物の様子

どういう実装になっているか?

1. 遷移の仕方


今回作成したアプリでは上図のように3つの画面を行き来できるようになっています。

FinishからHomeへは一方的にしか進めないというところがポイントになっています。

2. 遷移させる動きをする大枠を作成します。

ソースコードはこちら↓

void main() = > runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Navigation with Routes',
      initialRoute: '/',
      routes: {
        '/': (_) => new Home(),
        '/check': (_) => new Check(),
        '/finish': (_) => new Finish(),
      },
    );
  }
}

こちらではルーティングの設定をしています。
今回は3画面分の設定がありますが、設定する際に注意していただきたいのは
[/の設定を忘れないこと]or[initialRouteを設定すること]です。

初めは次のようなルーティングを行っておりました。

// initialRoute: '/', <- 記載なし
routes: {
  '/home': (_) => new Home(),
  '/check': (_) => new Check(),
  '/finish': (_) => new Finish(),
},

このような設定を行っていると初めにアクセスすべきクラスが見つからずエラーになってしまいます。

3. 3画面(Home,Check,finish)それぞれclassを作成します。

#Home

class Home extends StatelessWidget {
  @override 
  Widget build(BuildContext context){
    return new Scaffold(
      appBar: new AppBar(
        title: const Text('Home'),
      ),
      body: new Center(
        child: new RaisedButton(
          onPressed: (){
            Navigator.of(context).pushNamed('/check');
          }
        ),
      )
    );
  }
}

#Check

class Check extends StatelessWidget {
  @override
  Widget build(BuildContext context){
    return new Scaffold(
        appBar: new AppBar(
          title: const Text('Check'),
        ),
        body: new Center(
          child: new RaisedButton(
              onPressed: (){
                Navigator.of(context).pushNamed('/finish');
              }
          ),
        )
    );
  }
}

#Finish

class Finish extends StatelessWidget {
  @override
  Widget build(BuildContext context){
    return new Scaffold(
        appBar: new AppBar(
          title: const Text('Finish'),
        ),
        body: new Center(
          child: new RaisedButton(
              onPressed: (){
                Navigator.popUntil(context,ModalRoute.withName('/'));
              }
          ),
        )
    );
  }
}

ご覧になっていただいたように、遷移するだけの機能しか持ち合わせていないのですごくシンプルな構造です。
画面毎に違う点は、AppBarに設定しているTextとボタンを押した際に動作するNavigatorの処理だけですね。

今回は2種類の関数を用いています。[pushNamed]と[popUntil]ですね。
[pushNamed]はイメージしやすく扱いやすかったです。
関数名もpush,popと付いていてスタック構造をイメージすれば良いのだなと思いました。

問題は[popUntil]でした。
関数名も[pop]+[Unitl]で「あぁこいつは指定したところまでpopしてくれる関数なんだなぁ」と思いました。

そこで、

Navigator.popUntil(context,ModalRoute.withName('/home'));

と設定しました。「これでHome画面まで戻ってくれるぞ!」と動かした結果。。。

エラーになりました。

原因はルーティングの設定でした。

initialRoute: '/',
    routes: {
      '/': (_) => new Home(),
      '/home': (_) => new Home(),
      '/check': (_) => new Check(),
      '/finish': (_) => new Finish(),
    },

上記のような設定を行っていて、[/home]を指定すればHome画面まで戻ってくれるだろうと思い込んでいました。
Finish画面まで来た時に通ったルートは

[/] -> [/check] -> [/finish]

でした。[/home]というルートはpushしておらず見つからなくて当然ですね。
そのため、

Navigator.popUntil(context,ModalRoute.withName('/'));

とする必要がありました。
ルートを指定してpopする際は指定する値が正しい設定になっているか要確認ですね。

さいごに

今回、画面遷移を実装するにあたり主にルーティングの部分でつまずきました。
つまずいたポイントは以下2つです。
・[/のルーティング設定が存在するか]もしくは[initialRouteが設定されているか]
・ルートを指定してpopする際は指定する値が正しい設定になっているか

後になってみれば、エラー画面にも間違っている内容は書いているし、
公式のドキュメントにも正しい例が載っているにも関わらず理解するのに時間がかかったのは
悔やまれます。

今回、使用した関数は[pushNamed]と[popUntil]だけですが、
他にも画面遷移をする際に使用できる関数はいくつかあるようですので
用途に併せて使い分けたいですね。

ishimaruのブログ