0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Flutter初心者が力技で同じTextEditingControllerを複数使った話

Posted at

どういうこと?

名前を入力する欄が複数行あった場合、同じTextEditingControllerを使ってしまうと、入力された値が全てに反映されてしまいます。

スクリーンショット 2024-02-09 10.42.05.png

動的にしたい…

初めから入力する行数がわかっていれば、それぞれのTextEditingController を作ればいいわけですが、行を追加したり削除したりするような処理だといくら数が増えるかわからないわけです。
ReactであればuseFieldArrayという便利なものがあって、fieldに追加したり削除したりで動的に同じ値を持った入力フォームを簡単に作成できるんですが、Flutterではそういうやつがなさそうなので、悩みました…

要はindexで呼び出せばいいってわけ?

TextEditingControllerがリストになっていてループで回したときに指定したindexで欲しいとこのTextEditingControllerが呼び出せればいいから…

List<TextEditingController> nameControllers = List.generate(2, (i) => TextEditingController());

@override
Widget build(BuildContest context) {
  return Scaffold(
    child: ListView.builder(
      shrinkWrap: true,
      itemCount: nameControllers.length,
      itemBuilder: (context, index) {
      return Column(
        children: [
          TextField(
            controller: nameControllers[index],
            decoration: InputDecoration(labelText: 'name')
          )
        ]
      )
    }
  )
)}

これでだいたい近いことができました!

スクリーンショット 2024-02-09 10.54.41.png

でもこれだと、リストを作ってからだから動的ではないな…

あれ?複数のTextEditingControllerがあるときどうするんだ?

例えばメンバー表などで名前と年齢を入力するTextFieldがあり、行を追加したい場合、上記の方法だと、TextEditingControllerを指定できません。
呼び出す時に何かを指定しなきゃならないということは…Mapか?
ということで、

List<Map<String, TextEditingController>> memberControllers = [
  {
    'name':TextEditingController(),
    'age': TextEditingController(),
  }
];

で、呼び出す時はListView.builderを使って

ListView.builder(
 itemCount: memberControllers.length,
 itemBuilder: (context, index) {
   return Row(
     children: [
       SizedBox(
         width: 200,
         child: TextField(
           controller: memberControllers[index]['name'],
           decoration: InputDecoration(labelText: 'name')
           ),
       ),
       const SizedBox(width: 20.0),
       SizedBox(
         width: 200,
         child: TextField(
         controller: memberControllers[index]['age'],
         decoration: InputDecoration(labelText: 'age')
         )
       )
  ]);
 }
)

これでそれぞれを呼び出すことができました。
あとは行を追加するボタンとかをおもむろに追加します。

ElevatedButton.icon(  
    onPressed: () {  
      setState(() {  
        memberControllers.add({  
          'name': TextEditingController(),  
          'age': TextEditingController(),  
        });  
      });  
    },  
    icon: const Icon(Icons.add),  
    label: const Text('追加')
),

スクリーンショット 2024-02-09 11.26.04.png

解決

これでやりたいことができました。
調べ方が悪いのか求めることがなかなか出てこなかったので、なんとかかんとかやってみました。
動いてはいますが、やり方が正しいか不安なので、こうしたほうがいい、このやりかたは良くないなどありましたらぜひコメントくださると嬉しいです。
お読みいただきありがとうございました。

参考

参考にさせていただきました。ありがとうございます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?