[Flutter]スクロール可能なFormFieldの取り扱い
4 min readMay 18, 2020
本記事では、スクロール可能でinvisibleになりうるFormFieldの取り扱いについて解説します。
以下のような登録画面を作るとします。「利用規約」を開くと長い文章が表示されます。
この画面は以下のように実装されています。
ExpansionTile
を開いた状態の時、上部のTextFormField
は画面外に出ます。この状態で起こりうる問題を解説します。
再描画時に値が書き換えられてしまう
非表示にされたり、ListView
の要素が画面外にスクロールされたりした時、つまりInvisibleな状態になると、そのwidgetはdisposeされます。再び表示される際には初期化されるため、それまでの値が書き換えられてしまいます。
この問題は、下記の方法で解決することができます。
- 変更を保存し、
initialValue
に設定する
FormFieldの初期化時には、initialValue
が入力値として代入されます。これを指定していないもしくは定数を渡している場合に、再初期化時にこれまでの入力値が書き換えられることになります。FormFieldの値が変更されるたびに変数に代入し、その変数をinitialValue
として渡しておくことで、再び初期化されても変更を保持することができます。
SingleChildScrollView
を利用する
サンプルではスクロール可能要素をListView
として定義していますが、SingleChildScrollView
を利用することもできます。SingleChildScrollView
はスクロール可能な一つの要素を扱うwidgetで、画面外に出てもdisposeされません。これを用いることで再初期化を防ぐことができます。
Invisibleの時GlobalKeyから取得できない
サンプルではFormにGlobalKey
を設定し、下記のようにボタン押下時にcurrentState.validate()
を呼び出しています。
しかし、Form全体がinvisibleになるとdisposeされて、currentState
がnullになりvalidationを行うことができません。この問題の解決方法は以下の通りです。
- 画面全体をFormでwrapする
Form下部の要素(サンプルのExpansionTile
)もFormの子要素とすることで、invisibleになることはありません。可読性は劣るため推奨しません。
SingleChildScrollView
を利用する
先ほどの問題と同様にSingleChildScrollView
を用いることで、invisibleな状態でもGlobalKeyのcurrentStateが保持され続けます。