【 Flutter 】Flutter を 基礎 から 学習 ( スタートガイド編 ) part20 画面遷移

基礎 から 学ぶ Flutter 」という書籍で  学習 したことを ブログでアウトプットしていこうと思います。今回は スタートガイド編 ( part20 )です。

前回

【 Flutter 】Flutter を 基礎 から 学習 ( スタートガイド編 ) part19 画面遷移

今回も引き続き画面遷移についてです。

画面遷移

画面間のデータの受け渡し

ウィジェット生成時に引数で渡します。なんとも基本的な実装!
サンプルを入力してみました。渡された値をSecondPageのタイトルバーに表示します。

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: FirstPage(),
    );
  }
}

class FirstPage extends StatelessWidget {
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('First Page')),
      body: Center(
        // RaisedButtonは非推奨になった。
        child: ElevatedButton(
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(
                  builder: (context) {
                    return SecondPage('messageFromFirst');
                  },
                  // モーダル遷移
                  fullscreenDialog: true),
            );
          },
          child: Text('Next Page'),
        ),
      ),
    );
  }
}

class SecondPage extends StatelessWidget {
  final String messageFromFirst;
  SecondPage(this.messageFromFirst);
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Second Page')),
      body: Center(
        // RaisedButtonは非推奨になった。
        child: ElevatedButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: Text('Go back'),
        ),
      ),
    );
  }
}

実行してみました。
SecondPageのタイトル部分に渡した文字列が表示されているのがわかります。

元の画面にデータを渡す

遷移元、といえばよいでしょうか。
遷移先でいろいろデータを入力し、遷移元にそのデータを渡して表示する・・・なんていうシチュエーションはたくさんありますよね。

この場合はpop()の第2引数に設定してあげます。
型は何でもよいとのことなので、この第2引数に対して遷移元に渡したい情報すべてを格納してあげる想定なのかと思います。

サンプルを入力しました。
サンプルでは非同期処理が行われています。
・・・非同期処理でしか実現できないのでしょうか?
なにか理由があるのかもしれませんが今はわかりません。

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: FirstPage(),
    );
  }
}

class FirstPage extends StatelessWidget {
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('First Page')),
      body: Center(
        // RaisedButtonは非推奨になった。
        child: ElevatedButton(
          onPressed: () async {
            var message = await Navigator.push(
              context,
              MaterialPageRoute(
                  builder: (context) {
                    return SecondPage('messageFromFirst');
                  },
                  // モーダル遷移
                  fullscreenDialog: true),
            );
            // 遷移先からもらった結果を表示
            print(message);
          },
          child: Text('Next Page'),
        ),
      ),
    );
  }
}

class SecondPage extends StatelessWidget {
  final String messageFromFirst;
  SecondPage(this.messageFromFirst);

  Widget build(BuildContext context) {
    return Scaffold(
      //appBar: AppBar(title: const Text('Second Page')),
      appBar: AppBar(title: Text(messageFromFirst)),
      body: Center(
        // RaisedButtonは非推奨になった。
        child: ElevatedButton(
          onPressed: () {
            Navigator.pop(context, "SecondPageから戻った");
          },
          child: Text('Go back'),
        ),
      ),
    );
  }
}

実行してみました。

あれ?なにも表示されませんね。

と思ったら、printはコンソールに出力されるようです(笑
Android StudioのConsoleを確認したところ、ちゃんと出力されていました。

遷移先からもらった値を画面に表示したい場合はおそらくStatefulWidgetにしなければならないのではないかと思います。

こちらのページを参考に、見よう見まねで作成してみました。

【Flutter】 戻るボタンで遷移元画面に値を渡す方法 – Qiita

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: FirstPage(),
    );
  }
}

class FirstPage extends StatefulWidget {
  @override
  _FirstPage createState() => _FirstPage();
}

class _FirstPage extends State {
  String _result = "";

  @override
  void initState() {
    super.initState();
    _result = "遷移先に移動";
  }

  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('First Page')),
      body: Center(
          child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
        Text(
          _result,
          style: Theme.of(context).textTheme.headline5,
        ),
        // RaisedButtonは非推奨になった。
        ElevatedButton(
          onPressed: () async {
            var message = await Navigator.push(
              context,
              MaterialPageRoute(
                  builder: (context) {
                    return SecondPage('messageFromFirst');
                  },
                  // モーダル遷移
                  fullscreenDialog: true),
            );
            // 遷移先からもらった結果を表示
            print(message);
            setState(() {
              _result = message;
            });
          },
          child: Text('Next Page'),
        ),
      ])),
    );
  }
}

class SecondPage extends StatelessWidget {
  final String messageFromFirst;
  SecondPage(this.messageFromFirst);

  Widget build(BuildContext context) {
    return Scaffold(
      //appBar: AppBar(title: const Text('Second Page')),
      appBar: AppBar(title: Text(messageFromFirst)),
      body: Center(
        // RaisedButtonは非推奨になった。
        child: ElevatedButton(
          onPressed: () {
            Navigator.pop(context, "SecondPageから戻った");
          },
          child: Text('Go back'),
        ),
      ),
    );
  }
}

実行してみました。
こちらの方がわかりやすいですね!

最後に

データの受け渡し事態はそんなに大変では無い印象でした。
Dartの入れ子がなんとも(何度も口にしてしまいます)

今日はここまで!