🙄

[Flutter] 『SingleChildScrollView & Column』の代わりに『ListView』を使っていた時の失敗談

2022/08/19に公開

Flutterで『SingleChildScrollView & Column』の代わりに『ListView』を使っていた時の失敗談(?)を書いておきます。なお、個人開発での話です。
アホなミスなので、どうぞ嘲笑ってください。

どこでListViewを代わりに使っていたか

私の場合、Formの部品設置をListViewで行っていました。
コードは以下のような感じです。

return Form(
  key: _formKey,
  child: ListView(
    children: [
      TextFormField(
        controller: _nameController,
	validator: (name) {
	  if (name == null || name.isEmpty) {
	    return '名前を入力してください。';
	  }
	  return null;
	},
      ),
      // 以下にも複数のForm部品が設置されている
      
      ElevatedButton(
        onPressed: () {
	  // 送信処理
	},
	child: Text('送信'),
      ),
    ],
  ),
);

このように、普通はSingleChildScrollViewとColumnを使うような場面でもListViewを使用していました。

なぜ代わりにListViewを使っていたか

こちらの理由は単純で、『同じ見た目動作で、コードのネストを浅くできるから』です。

以下2つのコードは見た目的には同じになりますよね。

return SingleChildScrollView(
  child: Column(
    children: List.generate(20, (i) {
      return ListTile(
        title: Text('$i'),
      );
    }),
  ),
);
return ListView(
  children: List.generate(20, (i) {
    return ListTile(
      title: Text('$i'),
    );
  }),
);

「ListViewを使えばネストを浅くできるし、まぁこれでいっか!」という感じで使っていました。

どこでミスをしたか

私の場合、先程のFormのvalidatorが反応しない事象が発生しました。
これはなぜかというと、『ListViewは、スクロールされることによって表示されなくなった子Widgetを破棄するから』です。
適当な画像ですが、以下のような感じです。

送信ボタンが一番下にあるため、スクロールによって上に設置した部品Widgetが破棄されてしまい、validatorが反応しなかったわけです。
ListViewをSingleChildScrollViewとColumnに直したらvalidatorはしっかり反応しました。

まとめ

『SingleChildScrollView & Column』の代わりに『ListView』を使用するのはやめましょう。
各Widgetは適材適所の場所に配置しましょう。

Discussion