はじめに
まず始めに、本記事では、ダート言語とFlutterフレームワークを使ってシンプルなTODOアプリケーションを作成する方法について解説します。この記事は初心者向けに作られており、基本的なFlutterの概念やウィジェットの操作について理解していることを前提としています。
この記事で紹介しているアプリは下記のブランチにアップロードしていますのでこちらも参照してください
初めてのFlutter/Dartマルチプラットフォームアプリ開発チュートリアル
Flutter環境のセットアップ
まずはじめに、開発環境を整える必要があります。Flutterのインストールは公式ドキュメントを参照してください。Flutterを利用することで、iOSとAndroidの両方向けに一度にアプリを作成することが可能となります。
新規プロジェクトの作成
Flutterの環境設定が終わったら、新規プロジェクトを作成します。以下のコマンドをターミナルに入力します。
flutter create todo_app
cd todo_app
このコマンドを実行すると、todo_app
という名前の新しいFlutterプロジェクトが生成されます。ここで、cd todo_app
コマンドで作成したプロジェクトのディレクトリに移動します。
必要なパッケージのインストール
このTODOアプリでは、状態管理のためにprovider
パッケージを使用します。これをプロジェクトに追加するためには、providerをインストールしましょう
flutter pub add provider
pubspec.yaml
ファイルに以下のように追加されます
dependencies:
flutter:
sdk: flutter
provider: ^6.0.5
Todoリストのモデル作成
まずはじめに、Todoリストのモデルを作成します。以下のようにlib/models
ディレクトリを作成し、その中にtodo.dart
というファイルを作成します。
class Todo {
String title;
bool isDone;
Todo({required this.title, this.isDone = false});
}
このTodo
クラスは、タイトルとそのタスクが完了しているかどうかのフラグを保持します。
続いては、Todo
モデルのリストを管理するTodoList
クラスを作成します。このクラスはChangeNotifier
を継承します。ChangeNotifier
はFlutterのproviderパッケージに含まれるクラスで、状態の変更をリスナーに通知する役割を果たします。以下のようにlib/models
ディレクトリ内にtodo_list.dart
ファイルを作成します。
import 'package:flutter/foundation.dart';
import 'todo.dart';
class TodoList extends ChangeNotifier {
List _todos = [];
List get todos => _todos;
void addTodo(String title) {
_todos.add(Todo(title: title));
notifyListeners();
}
void toggleTodo(int index) {
_todos[index].isDone = !_todos[index].isDone;
notifyListeners();
}
}
TodoList
クラスには以下の2つのメソッドがあります。
addTodo
:新しいTodo
インスタンスをリストに追加します。追加後、notifyListeners
メソッドを呼び出してリスナーに状態の変更を通知します。toggleTodo
:指定されたインデックスのTodo
の完了状態を切り替えます。切り替え後、notifyListeners
メソッドを呼び出してリスナーに状態の変更を通知します。
ここで重要な点は、notifyListeners
メソッドを呼び出すことで、状態の変更をUIに反映することができます。具体的には、Consumer
ウィジェットやProvider.of
メソッドを通じて、状態の変更を購読しているウィジェットがリビルドされます。
これで、Todoリストを管理するモデルの作成が完了しました。次に、このモデルをアプリケーションの状態として提供する方法を見てみましょう。
UIの作成
次に、Todoアイテムを表示し、新しいTodoアイテムを追加するためのUIを作成します。screens
ディレクトリ内にhome_screen.dart
という名前の新しいファイルを作成します。
providerを使った状態管理を行うため、Consumerを使っています
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:todo_app/models/todo_list.dart';
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Todo List'),
),
body: Consumer(
builder: (context, todoList, child) {
return ListView.builder(
itemCount: todoList.todos.length,
itemBuilder: (context, index) {
return CheckboxListTile(
title: Text(todoList.todos[index].title),
value: todoList.todos[index].isDone,
onChanged: (bool? value) {
todoList.toggleTodo(index);
},
);
},
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () => _showAddTodoDialog(context),
child: const Icon(Icons.add),
),
);
}
void _showAddTodoDialog(BuildContext context) {
final todoTextController = TextEditingController();
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Todoの入力'),
content: TextField(
controller: todoTextController,
decoration: const InputDecoration(hintText: "Todoを入力してください..."),
),
actions: [
TextButton(
child: const Text('Cancel'),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: const Text('Add'),
onPressed: () {
Provider.of(context, listen: false)
.addTodo(todoTextController.text);
Navigator.of(context).pop();
},
),
],
);
},
);
}
}
このコードは、
でTextField
を通じて新しいTodoアイテムを追加する機能と、Todoアイテムの完了状態をトグルする機能、Todoアイテムを並べる機能を提供します
ダイアログの部分の画面を別ファイルにしておくのもありではと思いました
メインファイルの更新
最後に、main.dart
ファイルを以下のように更新します。これにより、TodoList
クラスのインスタンスがアプリ全体でアクセス可能になります。
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'models/todo_list.dart';
import 'screens/home_screen.dart';
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => TodoList(),
child: TodoApp(),
),
);
}
class TodoApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Todo List',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomeScreen(),
);
}
}
以上でシンプルなTODOアプリケーションの作成は完了です。このアプリでは新しいタスクの追加と追加したタスクの参照が可能です。
タスク完了と削除の機能追加
次にタスクの完了と削除を実装します。今回はタスクを長押ししたときに削除する機能を追加します。
最初にTodoListのモデルに削除する処理を追加します。今回はremoveTodoという名前でメソッドを追加します
import 'package:flutter/foundation.dart';
import 'todo.dart';
class TodoList extends ChangeNotifier {
final List _todos = [];
List get todos => _todos;
void addTodo(String title) {
_todos.add(Todo(title: title));
notifyListeners();
}
void toggleTodo(int index) {
_todos[index].isDone = !_todos[index].isDone;
notifyListeners();
}
void removeTodo(Todo item) {
_todos.remove(item);
notifyListeners();
}
}
杖技はhome_screen.dartのTodoのリストを表示しているListView.builderの部分を下記のように編集してタスク完了と削除機能を追加します
長押しするとタスクを削除することができ、完了にするを押下するとタスクの左側に✅マークが表示され、完了にするボタンが未完了にするボタンへと変化します
ListView.builder(
itemCount: todoList.todos.length,
itemBuilder: (context, index) {
final item = todoList.todos[index];
return ListTile(
title: Text(
item.title,
),
leading: item.isDone
? const Icon(Icons.done, color: Colors.green) : null,
trailing: ElevatedButton(
onPressed: () {
todoList.toggleTodo(index);
},
child: item.isDone ? const Text("完了にする") : const Text("未完了にする"),
),
onLongPress: () {
// 長押しすることで削除します
Provider.of(context, listen: false).removeTodo(item);
},
);
},
);
以上がFlutterを用いたシンプルなTODOアプリケーションの作り方でした。Providerを用いて状態管理を行うことで、アプリケーションのコードが明快で読みやすくなります。この手法を自身のプロジェクトに適用してみてください。