📝

[Flutter] TextFormFieldのいろいろ

2022/07/16に公開

TextFormFieldを使った上での気付きやエラー等をメモしていきます。

TextFormFieldはTextをFormに入力するためのwidget。
そのFormへの入力方法や、形式を必要に応じて様々な形に変更できます。

入力されるTextを右から表示

textAlign: TextAlign.right

入力されるTextを数字に限定

inputFormatters: [FilteringTextInputFormatter.digitsOnly]

0の入力をさせない

inputFormatters: [FilteringTextInputFormatter.deny(RegExp(r'^0+'))]

フォームへの入力可能な文字数を設定

maxLength: 300,
TextFormFieldにMaxLengthを用いることでフォームに入力できる文字数の限界を設定できます。上記のコードの場合であれば300字までのTextの入力が可能です

TextFormFieldの大きさを変更

SizedBoxでTextFormFieldを囲ってあげると横幅と高さをお好みの大きさに指定することができます。
TextFomField内で、にwidth/height を使ってサイズの変更を行おうとしていたのですが、それでは解決しませんでした。TextFormFieldはすでに決まったサイズを持っているため、この方法ではできません。
SizedBoxを使用することで解決できます。

SizedBox(
width: 100,
height: 50,
child: TextFormField(
    //formの中身
  ),),

このようにSizedBoxでTextFormFieldを囲ってあげると下の画像のように指定した大きさでFormが表示されます。
イメージ

Flexibleでも解消できる場合もあるようなので参考にしてみてください。↓
https://zenn.dev/masarufuruya/articles/flutter-row-textfield

validatorについて

TextFormFieldはバリデートという機能を持っています。バリーデートとは入力された内容が適切なものかどうかを判断すること。

例)入力必須のフォームに何も入力せずに次に進むボタンを押した場合には、エラーを表示。それ以外の場合はボタンを押しても何も表示をしない。

validatorを使用して上記のような判断する条件を書き出しておくと、条件に沿った適切なものかどうかを自動で判別してくれます。
ただ、Validatorを使用するにあたって2つ注意点があります。

  1. FormでTextformfieldを囲む

まず、バリデートしたいすべてのTextFormFieldをFormで囲わないといけません。例えば、TextFormFieldをColumnウィジェットで配列している場合には、TextFormFieldを囲っているColumnウィジェットごとFormで囲う必要があります。

参考コード

           Form(
            key: _formKey,
            child: Column(
              children: [
                TextFormField(
                  validator: (value) {
                    if (value == null || value.isEmpty) {
                      return 'Please enter some text';
                    }
                    return null;
                  },
                  decoration: const InputDecoration(
                    border: OutlineInputBorder(),
                    hintText: 'Enter a search term',
                  ),
                ),
                TextFormField(
                  decoration: const InputDecoration(
                    border: OutlineInputBorder(),
                    hintText: 'Enter a search term',
                  ),
                ),
                TextFormField(
                  decoration: const InputDecoration(
                    border: OutlineInputBorder(),
                    hintText: 'Enter a search term',
                  ),
                ),
                ),
              ],
            ),
          ),
  1. globalKeyを設定する

次にGlobalkeyの設定。バリデートした結果を判断材料として最後渡さないといけません。渡すときに必要になるのがこのGlobalKeyです。

final formKey = GlobalKey<FormState>();

上記のように、GlobalKeyを他の場所でも値を返せるようにformKeyとし、そのformKeyが持つ値はGolobalKeyの後ろの<>内に指定したFormState(フォームの状態)です。
そして、ボタンを押すとFormStateのValidateが呼ばれて各テキストフィールドでバリデートが実行され、フォームが適切なものかどうかを確認し、適切でない場合には、エラーが表示されます。

onPressed: () {
 if (formKey.currentState!.validate())

コード全体


class MyCustomFormState extends State<MyCustomForm> {
  final formKey = GlobalKey<FormState>();

  
  Widget build(BuildContext context) {
    return Form(
      key: formKey,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          TextFormField(
            validator: (value) {
              if (value == null || value.isEmpty) {
                return 'error';
              }
              return null;
            },
          ),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 16.0),
            child: ElevatedButton(
              onPressed: () {
                if (formKey.currentState!.validate()) {}
              },
              child: const Text('次へ'),
            ),
          ),
        ],
      ),
    );
  }
}

flutterのサンプルもあるのでそちらも確認してみてください。
https://docs.flutter.dev/cookbook/forms/validation

このようにvalidatorをTextFormField内に用意することで入力される内容にフィルターを掛けることができ、入力させる内容を指定する事や入力を必須にするなどといったことができます。
そしてこのvalidatorを使って私は100以上の数字しか許容しないフォームを作成しました。少しややこしかったので残しておきます。

Goal: 100以上の数字しか許容しないし、フォームの入力は必須

この場合のvalidatorのコードは以下のようにします。

validator: (value) {
                    if (value == null || value.isEmpty) {
                      return 'error';
                    }
                    final intvalue = int.tryParse(value) ?? 0;
                    if (intvalue < 100) {
                      return 'error';
                    }
                    return null;
                  },

はじめ私は value < 100 としていたがこれでは動きません。理由はvalueがString型だからです。しかし入力させたいのは100以上の数字。つまりintが代入されます。これではバリデートできないので、intをstringに変更します。
そのときに使用するのが、tryParseです。

final intvalue = int.tryParse(value) ?? 0;

tryParseを使用することで、入力されたintの数字をstringに変更し文字として認識します。
これで空やNullの場合と100以下の数字が入力された場合にはエラーが出るようになりました。また, ?? 0 を指定することで、Nullの場合には0を返すようにします。もちろん0は100より小さいので同様にエラーがでます。

GitHubで編集を提案

Discussion