見出し画像

作って学ぶ、Flutterアプリ開発 〜TODOアプリを作ろう〜

はじめに

この記事を読んでくださっている方は、Flutterでのアプリ開発またはモバイルアプリ開発に興味がある方かなと思います。
既にプログラミングを書いた事のある方、アプリ開発をした事のある方、はたまたプログラミングを一度も書いた事のない方。
色々かと思います。
この記事で作るアプリはプログラミングが初めての方でもできるように丁寧にコードを書いていこうと思います。(ただし、パソコンはある程度扱える前提で話を進めます。)
なのであまり怖がらずにチャレンジしてみてください!

開発環境セットアップ

さっそく、開発の準備をしていきましょう!
以前、開発環境に関する記事を書いたのでこちらを参照してください。
FlutterのDLページが一部画面と違っているのですが、「Choose your first type of app」という画面では「Android」を選択してみてください。

UI実装

さて、では早速アプリを作っていきましょうか。
AndroidStduioを起動して「New Flutter Project」を選択してください。

AndroidStudio

Flutter SDK Pathには環境構築でDLしてきたFlutter SDKのパスを設定してください。(私の画面はfvmというバージョン管理を使用している場合です)

AndroidStudio

Project name」に「todo_app」と入力してください。
入力が済みましたら「Create」ボタンを押して、プロジェクトを作成してください。
main.dart」というファイルにFlutterのサンプルコードが書かれています。
シミュレーターでアプリを起動して確認してみましょう。
シミュレーターの使い方はこちらの記事をご参照ください。

アプリが起動できましたらさっそくTodoアプリを作っていきましょう!


flutter

初期状態だと右下の「+」ボタンをタップすると、中央の数値が1つずつ増えていくという状態になっているかと思います。
それでは、この「+」ボタンをタップしたら入力画面を表示するように変更してみましょう。
入力画面はダイアログで作ってみます。
```floatingActionButton```というコードを探してください。

      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), /

今はこんな感じになっています。
これをこう変更しましょう。

      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // ボタンが押された時にここの実装が反映されます
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // T

スラッシュ二つはコメントという扱いになり、プログラムに影響を与えずにコメントを残しておけます。
onPressedには関数を渡す事ができます。
関数がなんだかわからない人は一旦わからなくて大丈夫です。
onPresseedには() {}と書くと覚えておいてください。
ダイアログについて詳しくはこちらの画面をご覧ください。

        onPressed: () {
          // ボタンが押された時にここの実装が反映されます
          showDialog(context: context, builder: (context) {
            return AlertDialog(
              title: const Text('タイトル'),
              content: const Text('内容'),
              actions: [
                TextButton(
                  onPressed: () {
                    Navigator.pop(context);
                  },
                  child: const Text('キャンセル'),
                ),
                TextButton(
                  onPressed: () {
                    Navigator.pop(context);
                  },
                  child: const Text('OK'),
                ),
              ],
            );
          });
        },

showDialog()を使うとダイアログを表示する事ができます。
ここではAlertDialogを表示しています。

flutter

右下の「+」ボタンをタップするとこんなダイアログが出るようになったと思います。
ダイアログ内の「OK」ボタンを「追加」に変更してみましょう。
どこを変えるとボタンのラベルを変更できるか分かりますか?
答えを見ずに変更できた方は筋がいいです!


答え

          showDialog(context: context, builder: (context) {
            return AlertDialog(
              title: const Text('タイトル'),
              content: const Text('内容'),
              actions: [
                TextButton(
                  onPressed: () {
                    Navigator.pop(context);
                  },
                  child: const Text('キャンセル'),
                ),
                TextButton(
                  onPressed: () {
                    Navigator.pop(context);
                  },
                  child: const Text('追加'), // ここです!
                ),
              ],
            );
          });
flutter

AlertDialog内のcontentを変更して文字を入力できるようにしてみましょう。

                  content: const TextField(
                    autofocus: true,
                  ),

TextFieldは文字を入力できるWIdgetです。
autofocusをtrueにしておくと、画面が表示された時にキーボードが自動で出てくるようになります。

flutter

ここまでできましたか?


次に、「追加」ボタンをタップした時に、入力された文字を元の画面にリスト形式で表示できるようにしてみましょう。

  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

_MyHomePageStateというclassの一番上にこんなコードがあると思います。
探してみてください。
このコードを思い切って消します。
で、こんな風に書き換えてください。

final _todoList = [];
final _textController = TextEditingController();

赤くなってエラーになった箇所がありますね。

            Text(
              '$_counter', //ここ
              style: Theme.of(context).textTheme.headlineMedium,
            ),

このTextWidgetも消します。
先ほど追加したTextFieldをちょっと修正します。

            content: TextField(
                    controller: _textController,
                    autofocus: true,
                  ),

controllerを追加します。
このcontrollerから入力された文字を取得する事ができます。
次にAlertDialog内の追加ボタンonPressedも修正します。

                    TextButton(
                      onPressed: () {
                        // 追加ボタンが押された時にここの実装が反映されます
                        setState(() {
                          _todoList.add(_textController.text);
                        });
                        _textController.clear();
                        Navigator.pop(context);
                      },
                      child: const Text('追加'),
                    ),

setStateはStatfuWidgetで使える機能で、この中で変更を加える事で画面上に反映されます。
追加ボタンが押された時に何をしているかというと、_todoListというリスト型の配列に入力された文字を追加しています。
その後、TextFieldに入力された文字をクリアしています。
ここまでできましたでしょうか?


それでは、_todoListの内容を画面に表示できるようにしてみましょう。
_todoListにはどんどん文字の配列が追加されていきます。
この文字をTextWidgetとして画面に表示します。
Scaffoldのbodyを変更します。

      body: Column(
        children: _todoList.map((e) => Text(e)).toList(),
      ),

Columnは縦方向にWidgetを並べる事のできるWidgetです。

mapというのはちょっと難しいのでわからない場合は一旦コピーで作成してください。
これでTextWidgetのリストができました。

flutetr

これでダイアログから入力された文字が画面に表示されるようになりました。
このままだと文字の表示がちょっとおかしいので、左寄せにしたいと思います。

      body: Column(
        crossAxisAlignment: CrossAxisAlignment.start, // ここ
        children: _todoList.map((e) => Text(e)).toList(),
      ),

ColumnにcrossAxisAlignmentを追加してください。
こうする事で左寄せにする事ができます。
さて、ここまでできましたでしょうか?


import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final _todoList = [];
  final _textController = TextEditingController();

  @override
  void dispose() {
    super.dispose();
    _textController.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: _todoList.map((e) => Text(e)).toList(),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // ボタンが押された時にここの実装が反映されます
          showDialog(
              context: context,
              builder: (context) {
                return AlertDialog(
                  title: const Text('TODOを追加'),
                  content: TextField(
                    controller: _textController,
                    autofocus: true,
                  ),
                  actions: [
                    TextButton(
                      onPressed: () {
                        Navigator.pop(context);
                      },
                      child: const Text('キャンセル'),
                    ),
                    TextButton(
                      onPressed: () {
                        // 追加ボタンが押された時にここの実装が反映されます
                        setState(() {
                          _todoList.add(_textController.text);
                        });
                        _textController.clear();
                        Navigator.pop(context);
                      },
                      child: const Text('追加'),
                    ),
                  ],
                );
              });
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}
flutter

最終的にこうなっていればOKです。
お疲れ様でした。

まとめ

簡単なアプリの実装方法について書いてみました。
どうでしょう?
難しかったですか?簡単だったでしょうか?
これを足がかりにもっと色々作ってみたいなと思っていただけると嬉しいです。
次はもうちょっと凝ったUIの作り方について書きたいと思います。
また、よろしくおねがいしますー!

この記事が気に入ったらサポートをしてみませんか?