Re:birth エンジニアリング

Flultterとテックブログと時々iOS

Flutterでパラメータ付き画面遷移の方法について学習する

前回はFlutter での画面遷移の方法について学習しました。 本日はそれをもとにして画面遷移時に遷移先の画面に値を渡す方法について学習します。

といってもそれほど難しくはなく発想はiOSAndroidと同じです。 それでは見ていきます。

画面間の値渡しの方法

簡単にいえば、遷移先のウィジェットに値が渡される変数を予めプロパティとして用意しておき、 遷移元はNavigatorpushの際に遷移先のウィジェットを引数指定して呼び出せばいいのです。

とりあえず、Navigatorのプッシュのメソッドの基本形を記載します。

Navigator.push(context,
    MaterialPageRoute(builder: (BuildContext context) => [遷移先ウィジェット]([引数]),),
);

あとは遷移先のウィジェットクラスで引数となるプロパティを宣言しておき、 引数を受け取るコンストラクタを書きます。

つまり、 1. 遷移先のウィジェットに値受け取り用の引数を用意する 2. 遷移先のウィジェットに引数受け取り用のコンストラクタを書く 3. Navigator.push で遷移する際に渡す値を指定する

このようになります。

サンプルソースコードについて

それでは、値渡し用のサンプルコードを書いていきます。

main.dart

import 'package:flutter/material.dart';
import 'package:practice_app/first_screen.dart';

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

class MyApp extends StatelessWidget {
  final title = 'Navigatorのサンプルコード';
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      debugShowCheckedModeBanner: true,
      title: 'Navigator App',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
        primaryColor: const Color(0xff2196f3),
        accentColor: const Color(0xff2196f3),
        canvasColor: const Color(0xfffafafa),
      ),
      home: FirstScreen(),
    );
  }
}

first_screen.dart

import 'package:flutter/material.dart';
import 'package:practice_app/second_screen.dart';

class FirstScreen extends StatefulWidget {
  @override
  _FirstScreenState createState() => _FirstScreenState();
}

class _FirstScreenState extends State<FirstScreen> {

  final _controller = TextEditingController();
  String _inputString;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("First Screen"),
      ),
      body: Column(
        children: <Widget>[
          Text('入力フォーム'),
          Padding(
            padding: EdgeInsets.all(10.0),
          ),
          TextField(
            controller: _controller,
            onChanged: changeTextField,
          ),
          Align(
            alignment: Alignment.centerLeft,
            child: FlatButton(
              child: Text('送信'),
              color: Colors.red,
              textColor: Colors.white,
              onPressed: (){
                if (_inputString.isEmpty) {
                  return;
                } else {
                  /// 3. Navigator.push で遷移する際に渡す値を指定する
                  Navigator.push(context,
                    MaterialPageRoute(builder: (BuildContext context) => SecondScreen(_inputString),
                    ),
                  );
                }
              },
            ),
          ),
        ],
      ),
    );
  }

  void changeTextField(String value) {
    _inputString = value;
  }
}

second_screen.dart

import 'package:flutter/material.dart';

class SecondScreen extends StatelessWidget {
  /// 1. 値受け取り用の変数
  final String inputString;
  /// 2. 引数受け取り用にinputStringの引数を指定したコンストラクタを書く
  SecondScreen(this.inputString);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Next Screen"),
      ),
      body: Center(
        child: Text('受け取った値: $inputString'),
      ),
    );
  }
}

これを実行すると次のような画面が表示されます。

最初の画面 テキスト表示
f:id:qed805:20200203002853p:plain
最初の画面、入力フォームに田中と入力
f:id:qed805:20200203002921p:plain
田中の値を受け取ってテキストとして表示させている

初期起動時は「入力フォーム」と書かれたTextとTextEditingControllerと送信用のFlatButtonの3つのウィジェットが表示されます。 TextEditingController に何かしら文字を入力してButtonをタップすると画面が遷移して次の画面が表示されます。 次の画面では入力された文字がそのまま表示される流れになっています。

アプリのヘッダーには戻る用のBackButtonがあるのが分かります。 これで最初のTextEditingControllerで入力された文字が渡されていることが分かりました。

モーダル遷移について

前回はBottomNavigationBarを追加したので書きませんでしたが、 Flutter でiOSのようにモーダル遷移ができないのかが気になりました。

Flutter でもモーダル遷移ができるようなのでそのやり方を共有しておきます。

Navigator.push(context,
    MaterialPageRoute(builder: (BuildContext context) => [遷移先ウィジェット]([引数]),),
    fullscreenDialog: true,  /// 追加
);

Navigator.pushの第3引数fullscreenDialogtrue を指定してあげればいいそうです。

今回で言えば、

first_screen.dart

import 'package:flutter/material.dart';
import 'package:practice_app/second_screen.dart';

class FirstScreen extends StatefulWidget {
  @override
  _FirstScreenState createState() => _FirstScreenState();
}

class _FirstScreenState extends State<FirstScreen> {

  final _controller = TextEditingController();
  String _inputString;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("First Screen"),
      ),
      body: Column(
        children: <Widget>[
          Text('入力フォーム'),
          Padding(
            padding: EdgeInsets.all(10.0),
          ),
          TextField(
            controller: _controller,
            onChanged: changeTextField,
          ),
          Align(
            alignment: Alignment.centerLeft,
            child: FlatButton(
              child: Text('送信'),
              color: Colors.red,
              textColor: Colors.white,
              onPressed: (){
                if (_inputString.isEmpty) {
                  return;
                } else {
                  /// 3. Navigator.push で遷移する際に渡す値を指定する
                  Navigator.push(context,
                    MaterialPageRoute(
                      builder: (BuildContext context) => SecondScreen(_inputString),
                      fullscreenDialog: true,
                    ),
                  );
                }
              },
            ),
          ),
        ],
      ),
    );
  }

  void changeTextField(String value) {
    _inputString = value;
  }
}

とすれば画面遷移がモーダル遷移に変わります。

このようにして3つの手順を行うと変数の値渡しができることを学びました。 非常に簡単ですね。