🍃
【Flutter】TODOアプリを作ってみた
はじめに
DroidKaigi 2025(オフライン)に参加したばかりのHaruです。アプリを作りたい欲が出てきたため、ほぼ初心者同然であるFlutterを用いて、TODOアプリを作ってみました。
やったこと
環境構築関係
- Flutterの環境構築
私がまとめたスクラップである、Flutter環境構築備忘録を参考にしていただければと思います。 -
flutter doctorを実行(flutter doctor --android-licenses実行後の結果)Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel stable, 3.27.1, on macOS 15.6.1 24G90 darwin-x64, locale ja-JP) [✓] Android toolchain - develop for Android devices (Android SDK version 35.0.0) [✓] Xcode - develop for iOS and macOS (Xcode 16.4) [✓] Chrome - develop for the web [✓] Android Studio (version 2025.1) [✓] VS Code (version 1.103.2) [✓] Connected device (2 available) [✓] Network resources • No issues found! -
flutter --versionFlutter 3.27.1 • channel stable • https://github.com/flutter/flutter.git Framework • revision 17025dd882 (9 months ago) • 2024-12-17 03:23:09 +0900 Engine • revision cb4b5fff73 Tools • Dart 3.6.0 • DevTools 2.40.2 -
flutter upgradeで最新版にしておく。(2025/9/15現在の最新版)Flutter 3.35.3 • channel stable • https://github.com/flutter/flutter.git Framework • revision a402d9a437 (12 days ago) • 2025-09-03 14:54:31 -0700 Engine • hash 672c59cfa87c8070c20ba2cd1a6c2a1baf5cf08b (revision ddf47dd3ff) (11 days ago) • 2025-09-03 20:02:13.000Z Tools • Dart 3.9.2 • DevTools 2.48.0 -
flutter docterを実行(flutter upgrade実行後の結果)Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel stable, 3.35.3, on macOS 15.6.1 24G90 darwin-x64, locale ja-JP) [✓] Android toolchain - develop for Android devices (Android SDK version 35.0.0) [✓] Xcode - develop for iOS and macOS (Xcode 16.4) [✓] Chrome - develop for the web [✓] Android Studio (version 2025.1) [✓] VS Code (version 1.103.2) [✓] Connected device (2 available) [✓] Network resources • No issues found!
TODOアプリ(雛形)を作成
-
flutter create mytodoappでアプリ作成 git initgit add .git commit -m "Initial Commit- リスト一覧画面(トップ画面)作成
- リスト追加画面作成
※5.6のコードは、Todoアプリ概要 | Flutterで始めるアプリ開発そのままです。 - AppBarを表示する
- リスト一覧を表示する
- リスト一覧のデザインを整える
※7~9のコードは、Todoリスト一覧画面 | Flutterで始めるアプリ開発そのままのコードです。 - リスト追加フォームを表示する
color: Colors.blue,はTodoリスト追加画面 | Flutterで始めるアプリ開発そのままだとエラーになるため、以下の様にする必要があった。style: ElevatedButton.styleFrom(backgroundColor: Colors.blue), - 入力されたテキストを扱う
- リスト一覧画面にデータを渡す
- リスト追加画面からのデータを受け取る
- データを元にリスト一覧を表示する
※11~15はTodoリスト追加画面 | Flutterで始めるアプリ開発そのままのコードです。
動作動画
以下のような動きのアプリが作成できます。

TODOアプリ(雛形にUpdateとDeleteを追加)
このアプリは、CRUDの、CreateとReadしかできていません。
以下で、Update(更新)とDelete(削除)を追加していきます。
Update(更新)処理を追加
-
body: ListView.builderのreturnを、以下のように変更して、onTapを追加するreturn Card( child: ListTile( title: Text(todoList[index]), onTap: () { print(todoList[index]); }, ), ); -
flutter pub add shared_preferencesを実行し、shared_preferencesをインストールする -
_showEditTaskDialogを作成
【Flutter】TODO / タスク管理アプリを作成する方法 #iOS - Qiitaを参考にした。Future<void> _showEditTaskDialog(int index) async { // 選択したn番目のタスクの名前を取得 final nameController = TextEditingController(text: todoList[index]); await showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text('タスクを編集'), content: Column( //Columnの長さを最小化する mainAxisSize: MainAxisSize.min, children: [ // タスク名を設定 TextField( controller: nameController, decoration: InputDecoration(labelText: 'タスク名'), ), SizedBox(height: 20), ], ), actions: [ // タスク編集をキャンセルするボタン TextButton( child: Text('キャンセル'), onPressed: () => Navigator.pop(context), ), // タスク編集を完了するボタン TextButton( child: Text('保存'), onPressed: () { // タスク名が空でないか確認して実行 if (nameController.text.isNotEmpty) { todoList[index] = nameController.text; // タスクの変更を保存 _saveTasks(); Navigator.pop(context); } }, ), ], ); }, ); setState(() {}); } -
_saveTasksを作成
【Flutter】TODO / タスク管理アプリを作成する方法 #iOS - Qiitaを参考にした。// タスクを保存する関数 Future<void> _saveTasks() async { SharedPreferences prefs = await SharedPreferences.getInstance(); await prefs.setStringList('tasks', todoList); // リストを保存 }
Delete(削除)処理を追加
-
_deleteTaskを作成
【Flutter】TODO / タスク管理アプリを作成する方法 #iOS - Qiitaを参考にした。// タスクを削除する関数 void _deleteTask(int index) { setState(() { todoList.removeAt(index); // タスクの削除を保存 _saveTasks(); }); } -
ListTileに以下を追加する参考: [Flutter]ListTileのtrailingに複数のアイコンを表示する方法trailing: Wrap( spacing: 8, // アイコンの間の幅を調整 children: [ IconButton( icon: Icon(Icons.delete), onPressed: () { _deleteTask(index); }, ), ], ),
参考: 【Flutter】 IconButton 使ってみた!【Material 3】 | 週刊Flutter大学 - [任意] 削除する前に、ダイアログを出すようにする
_deleteTask(index);を_confirmDeleteTask(index);にするように変更し、以下のコードを追加します。参考: FlutterでDismissible(スワイプして消す)とshowDialog(アラート確認)を組み合わせて実装する方法 #Flutter - Qiitavoid _confirmDeleteTask(int index) { showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text("削除確認"), // ダイアログのタイトル content: Text( "このアイテムを削除してもよろしいですか?", ), // ダイアログのメッセージ actions: <Widget>[ TextButton( onPressed: () => Navigator.of(context).pop(false), // キャンセルボタンを押したときの処理 child: Text("キャンセル"), ), TextButton( onPressed: () => { // 削除ボタンを押したときの処理 Navigator.of(context).pop(true), _deleteTask(index), }, child: Text("削除"), ), ], ); }, ); }
動作動画
以下のような動きのアプリが作成できます。

TODOアプリ(今までの変更に永続処理を追加)
-
_loadTasksを追加void initState() { super.initState(); // アプリ起動時に保存しているタスクを読み込む _loadTasks(); }// タスクを読み込む関数 Future<void> _loadTasks() async { SharedPreferences prefs = await SharedPreferences.getInstance(); List<String>? tasksJson = prefs.getStringList('tasks'); if (tasksJson != null) { setState(() { todoList = tasksJson; }); } } - 保存のときに、
_saveTasksを呼ぶように変更+nullのときには保存されないように変更if (newListText != null && newListText.toString().trim().isNotEmpty) { // キャンセルした場合は newListText が null となるので注意 setState(() { // リスト追加 todoList.add(newListText); _saveTasks();
参考: 【Flutter】TODO / タスク管理アプリを作成する方法 #iOS - Qiita
終わりに
TODOアプリは基本中の基本がさらえると思っています。
これを元に、何かしらのアプリを公開まで行きたいなと思っています。
Discussion