Chapter 05

Hands-on 2

takumma
takumma
2021.09.13に更新

リストに追加する

リストが表示できたので、次はリストを追加できるようにしてみましょう。
リストの追加は、右下のボタンを利用して実装することにします。

まずはリストに追加する関数 _addTodo()を実装しましょう。配列に文字列を追加したときにリストも変更されるように、 setState() を使います。add() は配列に引数の値を追加するメゾットです。
なお _incrementCounter()_counter は使わないので削除してかまいません。

my_home_page.dart
  class _MyHomePageState extends State<MyHomePage> {
    
-   int _counter = 0;
    
    final List<String> _todoItems = [
      // 略
    ];

-   void _incrementCounter() {
-     setState(() {
-       _counter++;
-     });
-   }
  
+   void _addTodo(String title) {
+     setState(() {
+       _todoItems.add(title);
+     });
+   }

そして、追加した _addTodo() がボタンを押したときに呼び出されるように指定しましょう。
押されたときに呼び出すのは onPressed で指定します。floatingActionButton を以下のように変更しましょう。

my_home_page.dart
  floatingActionButton: FloatingActionButton(
-   onPressed: _incrementCounter,
+   onPressed: () => _addTodo("追加したTODO"),
-   tooltip: 'Increment',
+   tooltip: 'Add Todo',
    child: const Icon(Icons.add),
  ),

右下のボタンを押すと、リストにカードが追加されていきます。

リストに追加は出来ますが、決まった文字ではなく自分で入力した文字を追加できるようにしたいですよね。

ということで次は TODO を入力する新規作成ページを実装していきます。
まずは右下のボタンを押したら新規作成ページに遷移するように実装しましょう。

新規作成ページ

まずは新しく新規作成ページを作ります。/lib/create_page.dart というファイルを作成しましょう。
中身はあとで変更するのでとりあえず以下のようにしてください。

create_page.dart
import 'package:flutter/material.dart';

class CreatePage extends StatefulWidget {
  const CreatePage({Key? key}) : super(key: key);

  
  State<CreatePage> createState() => _CreatePageState();
}

class _CreatePageState extends State<CreatePage> {

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Create TODO"),
      ),
      body: const Center(
        child: Text("新規作成ページ"),
      ),
    );
  }
}

この時点でのディレクトリ構成は以下のようになります。

ディレクトリ構成
flutter_hands_on(プロジェクトのルート)
├── lib
│   ├── create_page.dart
│   ├── main.dart
│   └── my_home_page.dart
└── ...

次はこの画面に遷移できるように実装しましょう。

画面遷移

今回は my_home_page の右下の floatingActionButtion を押したときに遷移をしたいので、 floatingActionButtion の onPressed に create_page へ遷移する処理を記述します。
ページへ遷移するときは、Navigator.of(context).push() を呼び出します。

my_home_page.dart
  floatingActionButton: FloatingActionButton(
-   onPressed: () => _addTodo("追加したTODO"),
+   onPressed: () => Navigator.of(context).push(MaterialPageRoute(builder: (context) => CreatePage())),
    tooltip: 'Add Todo',
    child: const Icon(Icons.add),
  ),

また、create_page から my_home_page に戻るボタンも作りましょう。
前のページに戻るには、Navigator.pop(context) を呼び出します。

create_page.dart
- body: const Center(
-   child: Text("新規作成ページ"),
+ body: Center(
+   child: Column(
+     mainAxisSize: MainAxisSize.min,
+     children: [
+       const Text("新規作成ページ"),
+       ElevatedButton(
+         child: const Text("Back"),
+         onPressed: () => Navigator.pop(context),
+       ),
+     ]
+   ),
  ),

my_home_page で右下のボタンを押すと create_page に遷移し、create_page でボタンを押すと my_home_page に戻ります。

入力フォームの作成

次は TODO を入力するフォームを作成しましょう。
create_page に、入力した文字を入れる変数 _title を追加します。

create_page.dart
  class _CreatePageState extends State<CreatePage> {
  
+   String _title = "";

そしてテキストフォームの Widget である TextField を追加します。

create_page.dart
  body: Center(
    child: Column(
      mainAxisSize: MainAxisSize.min,
      children: [
-       const Text("新規作成ページ"),
+       const Text("TODOを入力してください"),
+       TextField(
+         onChanged: (String text) => _title = text,
+       ),
        ElevatedButton(
          child: const Text("Back"),
          onPressed: () => Navigator.pop(context),
        ),
      ],
    ),
  ),

これで入力フォームが作成できました。

次はこの入力したテキストを TODO リストへ追加できるようにしていきましょう。

my_home_page に入力したテキストを渡す

create_page で入力したテキストを my_home_page に渡すように実装してみましょう。
前の画面へ戻るときに値を渡したいときは、Navigator.pop() の第二引数に渡したい値を指定します。

create_page.dart
  body: Center(
    child: Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        const Text("TODOを入力してください"),
        TextField(
          onChanged: (String text) => _title = text,
        ),
        ElevatedButton(
-         child: const Text("Back"),
+         child: const Text("Add"),
-         onPressed: () => Navigator.pop(context),
+         onPressed: () => Navigator.pop(context, _title),
        ),
      ],
    ),
  ),

そして前の画面(my_home_page)では以下のようにすることで、値を受け取ることができます。

my_home_page.dart
  floatingActionButton: FloatingActionButton(
-   onPressed: () =>  Navigator.of(context).push(MaterialPageRoute(builder: (context) => CreatePage())),
+   onPressed: () async {
+     final String title = await Navigator.of(context)
+       .push(MaterialPageRoute(builder: (context) => CreatePage()));
+   },
    tooltip: 'Add Todo',
    child: const Icon(Icons.add),
  ),

これで値を受け取ることができました。

受け取ったテキストを TODO リストに追加

リストに追加するのは、テキストを受け取った後に _addTodo() を呼び出すだけです。

my_home_page.dart
  floatingActionButton: FloatingActionButton(
    onPressed: () async {
      final String title = await Navigator.of(context)
        .push(MaterialPageRoute(builder: (context) => CreatePage()));
+     _addTodo(title);
    },
    tooltip: 'Add Todo',
    child: const Icon(Icons.add),
  ),

これで、

  1. my_home_page から create_page に遷移。
  2. create_page で TODO を入力。
  3. ボタンを押すと my_home_page に戻る。
  4. 入力された TODO をリストに追加する。

という一連の流れが実装できました。

しかしこのままだと何も入力して戻ったときや、左上をタップして戻ったときなどにエラーが起こってしまうのでそのための処理をしておきましょう。

my_home_page.dart
  floatingActionButton: FloatingActionButton(
    onPressed: () async {
-     final String title = await Navigator.of(context)
+     final String? title = await Navigator.of(context)
        .push(MaterialPageRoute(builder: (context) => CreatePage()));
-     _addTodo(title);
+     if (title != null && title != "") _addTodo(title);
    },
  ),

これで TODO を追加する機能が実装できました。

次のチャプターでは TODO の削除ができるように実装していきましょう。