[Flutter]スクロール可能なFormFieldの取り扱い

Satsuki Hashiba
4 min readMay 18, 2020

--

本記事では、スクロール可能でinvisibleになりうるFormFieldの取り扱いについて解説します。

Photo by Tobias Keller on Unsplash

以下のような登録画面を作るとします。「利用規約」を開くと長い文章が表示されます。

この画面は以下のように実装されています。

ExpansionTileを開いた状態の時、上部のTextFormFieldは画面外に出ます。この状態で起こりうる問題を解説します。

再描画時に値が書き換えられてしまう

非表示にされたり、ListViewの要素が画面外にスクロールされたりした時、つまりInvisibleな状態になると、そのwidgetはdisposeされます。再び表示される際には初期化されるため、それまでの値が書き換えられてしまいます。

スクロールすると、TextFormFieldに入力していた値が消える

この問題は、下記の方法で解決することができます。

  • 変更を保存し、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が保持され続けます。

--

--