【Flutter】TextEditingController使ってTextFieldに初期値を 持たせて表示する
はじめに
今回は以下動画を参考にして自分なりに作ってみたサンプルとその説明になります。
TextEditingController使った方法は動画内の該当箇所からわかりやすく説明されてますので、
こちらも参考にしてみてください。
YouTubeのvideoIDが不正です
この記事がどなたかの参考になれば幸いです。
また誤り等ございましたらご指摘いただけると幸いです。
作ったもの
今回はtodo一覧画面で表示されているtodoを編集画面で編集したいといった場合、
一覧画面で表示されているtodoを編集画面のTextFieldにそのまま表示するといったケースを想定してTodoアプリっぽいものを作ってみました。
Providerで状態管理を行い、UIとロジックを分けてファイルを作ってます。
一覧ページでtodo一覧を表示し、編集アイコンをタップすると編集画面に
移動→一覧ページのtodoがTextFieldに入った状態で表示されます。(実際に編集はできません)
環境
MacOS 12.1
Flutter (Channel stable, 2.10.0)
Dart SDK version: 2.16.0 (stable)
provider: ^6.0.2
ファイル一覧
- main.dart
todo一覧表示画面 - main_model.dart
一覧画面の状態管理 - edit_todo_page.dart
todo編集画面 - edit_todo_model.dart
編集画面の状態管理 - todo.dart
todoのオブジェクトTodoを定義しているファイル
実際のアプリ
Simulator Screen Recording - iPhone 13 - 2022-02-14 at 18.00.20.gif
各ファイルでの作業の流れ
1. main.dart
- Todo(ListTileに表示されるtodoのtitleを持っているクラス)を画面遷移で使うNavigator.pushで使われるeditTodoPage()の引数でわたす
2. edit_todo_page.dart
- Todoをコンストラクタで受け取って初期化する
- ChangeNotifierProviderでcreateされるmodel(EditTodoModel)の引数でTodoをedit_todo_modelにわたす
3. edit_todo_model
- Todoを引数にして初期化処理をする。edit_todo_pageのTextFieldで使うTextEditingControllerの初期化もこのコンストラクタでやっておく。
各ファイルの説明
main_model.dart
TodoをListViewで表示するため以下のような感じで用意してます。
import 'package:flutter/material.dart';
import 'package:todoapp/todo.dart';
class MainModel extends ChangeNotifier {
// todoListを手動で作成。ListViewで表示するためListにしておく。
List<Todo> todoList = [Todo('トイレ掃除'), Todo('犬の散歩')];
}
todo.dart
Todoを定義。ListTileで表示されるtitleを持っている。このtilteをedit_todo_pageのTextFieldで
表示したい
class Todo {
Todo(this.title);
String title;
}
main.dart
- main.dart→edit_todo_pageへentitiy(Todoオブジェクト)をわたしたいので、
edit_todo_pageへの画面遷移時に使うNavigator.pushで渡すedit_book_pageのコンストラクタの引数にTodo todoを入れる。
※todoList
はmain_model.dartで持っているTodoのリスト。
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:todoapp/main_model.dart';
import 'edit_todo/edit_todo_page.dart';
Future<void> main() async {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return MaterialApp(
title: 'TODO アプリ',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MainPage(),
);
}
}
class MainPage extends StatelessWidget {
const MainPage({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return ChangeNotifierProvider<MainModel>(
create: (_) => MainModel(),
child: Scaffold(
appBar: AppBar(
title: const Text('TextFieldに初期値を持たせるサンプル'),
),
body: Consumer<MainModel>(
builder: (context, model, child) {
final todoList = model.todoList;
return ListView(
children: todoList
.map(
(todo) => ListTile(
trailing: IconButton(
icon: const Icon(Icons.edit),
onPressed: () async {
//Todo :画面遷移
await Navigator.push(
context,
MaterialPageRoute(
// 1. 遷移先の編集画面EditTodoPage()にTodoをわたす
builder: (context) => EditTodoPage(todo),
),
);
},
),
title: Text(todo.title),
),
)
.toList(),
);
},
),
),
);
}
}
edit_todo_page.dart
- edit_book_pageのconstractorに引数にTodoを持たせておく。
- main.dartからTodoを受け取るため、変数を用意する。
(これでこのpageは必ず、引数にTodoを入れないと使えなくなる。) - ChangeNotifierProviderでcreateに入れるmodelのコンストラクタの引数にTodoを入れる
- TextFieldのcontrollerにmodelのTextEditingControllerを入れる
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../todo.dart';
import 'edit_todo_model.dart';
class EditTodoPage extends StatelessWidget {
// 1. Todoを受け取るため、constructorの引数に指定しておく。
const EditTodoPage(this.todo, {Key? key}) : super(key: key);
// 2. Todoを受け取るための変数を用意。
final Todo todo;
Widget build(BuildContext context) {
return ChangeNotifierProvider<EditTodoModel>(
// 3. 受け取ったTodoをさらにモデルにわたす。
create: (_) => EditTodoModel(todo),
child: Scaffold(
appBar: AppBar(
title: const Text('編集画面'),
),
body: Consumer<EditTodoModel>(builder: (context, model, child) {
return Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
TextField(
// 4. TextEditingControllerのtextはmodelで初期化されているので、
// main.dartのtextを持っている。
// そのため画面が描画されたときにtextが表示される。
controller: model.todoEditTextEditingController,
onChanged: (text) {
// 入力欄でテキストが編集された時にやること。
},
),
const SizedBox(
height: 16,
),
ElevatedButton(
onPressed: () {
// 入力されたtextを元にデータベースを更新する処理などをやる
},
child: const Text('編集'),
)
],
),
);
}),
),
);
}
}
edit_book_model
- Todoを受け取るためにconstructorで初期化処理。
- constructorで初期化するためのTodoも定義しておく。
- edit_todo_page.dartでTextFieldで使うためのTextEditingControllerを定義する。
import 'package:flutter/material.dart';
import 'package:todoapp/todo.dart';
class EditTodoModel extends ChangeNotifier {
// 1. Todoを受け取るためにconstructorで初期化処理。
EditTodoModel(this.todo) {
// TextEditingControllerのtextにTodoの持っているtitleを入れる
todoEditTextEditingController.text = todo.title;
}
// 2. constructorで初期化するためのTodoを定義しておく。
Todo todo;
// updateの時に入力されるtext用に用意
String? updateTodoText;
// 3. TextFieldで入力されたtextを扱うためのTextEditingController
final TextEditingController todoEditTextEditingController =
TextEditingController();
// TextEditingControllerをdisposeする。
void dispose() {
todoEditTextEditingController.dispose();
super.dispose();
}
}
参考サイト
最後に
ここまで読んでいただきありがとうございました!
Discussion