一番下に入力フォームを作ります。入力フォームはTextFieldというウィジットで簡単に作れます。
ListViewとTextFieldを縦並びにしたいのでこの二つをColumnに追加しましょう。
ここで便利機能の紹介です。
まず👇の画像の場所にカーソルを合わせて、
option + enterを押すと、

選択肢が出てくるのでWrap with Columnをクリック。ListViewがColumnの子になり、childrenの中の一つになりました。
これを「ListViewをColumnでラップした」と言います。
child: Column(
children: [
ListView.builder(
itemCount: todoList.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(todoList[index]),
leading: Radio<bool?>(
value: false,
groupValue: null,
onChanged: (bool? value) {
clickDone(index);
},
),
);
},
),
],
),

また、ListViewをColumnの中で使うときは高さを指定してあげないといけないというルールがあります。
なので、ListViewをExpandedでラップしましょう。操作は先ほどと同じです。
こうすることで、今回の場合残りの高さ全てがListViewに割り当てられ、高さが明確になります。
child: Column(
children: [
Expanded(
child: ListView.builder(
itemCount: todoList.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(todoList[index]),
leading: Radio<bool?>(
value: false,
groupValue: null,
onChanged: (bool? value) {
clickDone(index);
},
),
);
},
),
),
],
),
ではColumnの中にTextFieldも追加しましょう。
),
SafeArea(
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: TextField(),
),
),
],
変更後: 画面下部にTextFieldができているはずです👇

次にTextFieldの横に送信ボタンを作成します。今回ボタンはIconButtonを使って作成します。
TextFieldとIconButtonを横並びにしたいのでまずはTextFieldをRowでラップしましょう。
child: Row(
children: [
TextField(),
],
),
先ほどと同じで、Rowの中でTextFieldを使うときは横幅を設定してあげないといけないので、TextFieldをExpandedでラップしましょう。
child: Row(
children: [
Expanded(
child: TextField(),
),
],
),
そうしたらRowにIconButtonを追加しましょう。onPressedプロパティは一旦nullを入れておきます。
child: Row(
children: [
Expanded(
child: TextField(),
),
IconButton(
icon: Icon(Icons.send),
color: Colors.blue,
onPressed: null,
)
],
),
変更後: TextFieldの右横に送信ボタンが表示されているはずです👇

では送信ボタンがタップされた時に行いたい処理を関数にしてonPressedに設定しましょう。
今回はまず、todoListに新しいTodoという文字列を追加する処理を書いてみましょう。画面の更新をするためにsetStateの中に書くことも忘れずに。
}
void sendTodo() {
setState(() {
todoList.add('新しいTodo');
});
}
void clickDone(int index) {
...
}
そして今作った関数sendTodoをonPressedプロパティに設定しましょう。
IconButton(
icon: Icon(Icons.send),
color: Colors.blue,
onPressed: sendTodo,
)
変更後: 送信ボタンをタップでリストに追加されるようになっているはずです👇

TextFieldに入力された文字列をtodoListに保存したいです。そのために、TextFieldをTextEditingControllerの管理下におきましょう。
まずTextEditingContollerをインスタンス化しましょう。
class _MyHomePageState extends State<MyHomePage> {
List<String> todoList = ['ボールペンを買う', '本を読む', '電話をする'];
TextEditingController controller = TextEditingController();
Widget build(BuildContext context) {
...
}
今インスタンス化したcontollerをTextFieldの controllerプロパティに設定しましょう。
Expanded(
child: TextField(controller: controller),
),
これでTextFieldをcontrollerで管理することができるようになりました。
ではこれを使ってTextFieldに入力された文字列をリストに追加できるように処理を書き換えましょう。
void sendTodo() {
setState(() {
todoList.add(controller.text);
controller.clear();
});
}
変更後: 👇完成!!!

これにて完成です、お疲れ様でした。
今は空の文字列でもリストに追加されてしまいます。
空の文字列Todoがリストに登録されないようにしてみてください。
