Skip to content

6 実践4 画面間の受け渡し

Kenichiro Watanabe edited this page Jul 25, 2018 · 4 revisions

TODOアプリ実践④ 画面間の受け渡し

画面と画面の間で値を受け渡す

  • NavigatorとMaterialRouteを使って画面遷移できることはわかった

  • 同じ仕組みを使って、画面の間で値を受け渡すことが可能

  • class AddPageで、テキスト入力の結果を取得するためにTextEditingControllerを定義してTextFieldに紐づける

  • 右上ナビゲーションをタップした時に、Navigator.pop()を使って戻り値を指定して、画面を明示的に閉じる

  • 元画面側で、then()を使ってNavigator.pop()した結果を受け取る

import 'package:flutter/material.dart';

//-------------------------------------
// メイン関数: 全てはここから始まる!
void main() {
  // アプリの起点となるrunApp()関数の引数に、
  // Widgetを渡してあげると、それが画面の起点となって表示される
  runApp(new MyApp());
}

//-------------------------------------
// StatelessWidget: アプリのルート画面
// MyAppは実際には画面を持っておらず、その中身に描画させている
class MyApp extends StatelessWidget {
  // Widgetは必ずbuild()というメソッドをオーバーライドして、
  // 戻り値として、画面に表示したいWidgetを返す
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new MyHomePage(),
    );
  }
}

//-------------------------------------
// StatefulWidget: 実際の画面
// 常に固定の画面部品を表示させたい時 = StatelessWidgetを使う
// 状態によって画面部品の表示を変化させたい時 = StatefulWidgetとStateを使う
class MyHomePage extends StatefulWidget {
  // StatelessWidgetと違って、build()メソッドは持っていない
  // そのかわりに、createState()メソッドをオーバーライドして、build()メソッドを持つStateインスタンスを返してあげる
  @override
  _MyHomePageState createState() {
    return new _MyHomePageState();
  }
}

// TODO項目
class Entry {
  // ラベル文言
  String label;
  // チェック状態
  bool isChecked;

  Entry({this.label, this.isChecked = false});
}

// MyHomePageクラスの相方: _MyHomePageStateクラス
// StatefulWidgetの場合は、このStateに主な処理を書いていく
class _MyHomePageState extends State<MyHomePage> {
  // TODOリスト
  List<Entry> entries = [
    new Entry(label: 'あへあへ', isChecked: true),
    new Entry(label: 'どんどん'),
  ];

  // 画面に描画するWidgetを返す
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Flutter Demo Home Page'),
      ),
      body: ListView.builder(
        itemCount: entries.length,
        itemBuilder: (BuildContext context, int index) {
          return Row(
            children: <Widget>[
              Checkbox(
                value: !entries[index].isChecked,
                onChanged: (bool checked) {
                  print(checked);
                  setState(() {
                    entries[index].isChecked = checked;
                  });
                },
              ),
              Text(entries[index].label),
            ],
          );
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Navigator
              .push(
                  context,
                  new MaterialPageRoute<Entry>(
                      builder: (context) => new AddPage()))
              .then((Entry newEntry) {
            setState(() {
              entries.add(newEntry);
            });
          });
        },
        child: new Icon(Icons.add),
      ),
    );
  }
}

class AddPage extends StatelessWidget {
  final TextEditingController textController = new TextEditingController();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('TODO追加'),
        actions: <Widget>[
          new IconButton(
            icon: const Icon(Icons.add_circle_outline),
            onPressed: () {
              String label = textController.text;
              Entry newEntry = new Entry(label: label);
              Navigator.pop(context, newEntry);
            },
          ),
        ],
      ),
      body: TextField(
        controller: textController,
      ),
    );
  }
}

追加でやってみよう!

  • もしテキスト入力しなかった場合にエラーにする方法
  • 何も入力せずに戻った場合にエラーを出さないようにする