2020/10/17 Flutter : Build a form with validationの訳

テキストフィールドにユーザが情報を入力することが必要な場面がapp(アプリケーション・サービス)にはあります。例えば、メールアドレスとパスワードのセットを用いて、ユーザーにログインしてもらう必要がある場合です。

appを安全で利用しやすいものにするために、ユーザーから提供されたデータが有効なデータかを確認する必要があります。もしユーザーが正しいデータをフォームに入力した場合、処理を進めます。不正なデータでサブミットしようとした場合、エラーメッセージを表示して、何が問題かをユーザーに示す必要があります。

このサンプルでは、一つのテキストフィールドを持つフォームにバリデーションを追加する方法を以下のステップで学んでいきます。

 

  1. GlobalKeyを用いてFormを生成する。
  2. TextFormFieldをバリデーションロジックと共に追加する。
  3. バリデーションとサブミットを行うためのボタンを設置する。

1.GlobalKeyを用いてFormを生成する。

まずFormを生成します。Formウィジェットは複数のフォームフィールドをグループ化しバリデートするためのコンテナとしての役割を持ちます。

フォームを生成する時、GlobalKeyを用意します。このGlobalKeyによりそれぞれのフォームを一意(ユニーク)に識別します。そしてこの後のステップでバリデートできるようになります。

// カスタムフォームウィジェットを定義します。

class MyCustomForm extends StatefulWidget {
  @override
  MyCustomFormState createState() {
    return MyCustomFormState();
  }
}

// MyCustomFormウィジェットに対応するStateクラスを定義します。
// このクラスがフォームに関するデータを保持します。
class MyCustomFormState extends State<MyCustomForm> {
  // フォームウィジェットを一意(ユニーク)に識別するし、
  // フォームのバリデーションを可能にするためにglobal keyを生成します。 
  //
  // Note:`GlobalKey<FormState>`であり、
  // ↓GlobalKey<MyCustomFormState>.ではないので注意してください。
  final _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    // Build a Formウィジェットをビルドして、keyパラメータに、先ほど
    // 生成した_formKeyを指定します。
    return Form(
      key: _formKey,
      child: Column(
        children: <Widget>[
              // ここにTextFormFields と ElevatedButton を配置します。
        ]
     )
    );
  }
}

Tip:GlobalKeyを使うFormにアクセスするのにおすすめの方法です。

しかし、あなたのアプリのウィジェットツリーがもっと複雑な場合、Form.of()メソッドによりネストしたウィジェット群からフォームにアクセスする方法もあります。


2.バリデーションロジックと共にTextFormFieldを追加する。

Formを設置しても、それだけではユーザーが文字を入力するユーザーインターフェースが無い状態です。それはTextFormFieldウィジェットの仕事です。TextFormFieldウィジェットは、マテリアルデザインのテキストフィールドを描画し、バリデーションエラーが発生した時にその旨を表示することができます。

TextFormFieldウィジェットのvalidatorパラメータにコールバック(無名関数)を設定することでバリデーションロジックを指定します。ユーザーの入力が不正と判断された場合、validatorコールバックはエラーメッセージを含む文字列を返します。エラーが無い場合(バリデーションの結果有効な入力と判断された場合)、validatorコールバックはnullを返すようにします。

下記のサンプルは、何らかの入力が必要なTextFormFieldのためのvalidatorコールバックの例です。もし入力が無い(入力が空(から))の場合、親切なエラーメッセージを返します。

TextFormField(
  // The validator receives the text that the user has entered.
  //vqlidatorコールバックは引数として入力された文字列を受け取るので、
  //それを基にバリデーションコードを記述する。
  validator: (value) {
    if (value.isEmpty) {
      return 'Please enter some text';
    }
    return null;
  },
);

 


3.フォームをバリデートし、サブミットするボタンを配置する。

テキストフィールドとフォームを設置しました。次にユーザーがデータをサブミット(送信・提出)するために押すボタンを設置しましょう。

ユーザーがサブミットボタンを押してフォームのサブミットを試みた時、フォームが不正でないかチェック(バリデート)します。バリデート成功(有効なデータ)の場合、成功した旨のメッセージをユーザーに対して表示します。

不正なデータの場合(テキストフィールドが空だった場合)、エラーメッセージを表示します。

ElevatedButton(
  onPressed: () {
    // ↓バリデート成功の場合trueを返します。バリデート失敗の場合falseを返します。
    if (_formKey.currentState.validate()) {
      //ここではバリデート成功の場合スナックバーを表示します。
      //実際は、バリデート成功後サーバーに連絡したりデータベースにデータを
      //書き込んだりすることが多いです。

      Scaffold
          .of(context)
          .showSnackBar(SnackBar(content: Text('Processing Data')));
    }
  },
  child: Text('Submit'),
);

どのように動きますか?

フォームをバリデートするために、step1で作った_formKeyを使います。

_formKey.currentState()メソッドを使ってFormStateにアクセスすることができます。FormStateは、Formをビルド(生成)した時にFlutterによって自動的に生成されます。

_formKey.currentState()メソッド、というなら上記サンプルのif文の条件も

if( _formKey.currentState().validate() )

となるのではないか?と思うがとりあえず原文通り訳す。

FormStateクラスにはvalidate()メソッドがあります。validate()メソッドが呼び出されると、フォーム内のそれぞれのテキストフィールド(TextFormFieldウィジェット)に設定したvalidator()メソッドを実行します。

フォーム内の全てのテキストフィールドのバリデートが成功した場合、validate()メソッドはtrueを返します。

フォーム内のどこかのテキストフィールドでエラーが発生した(バリデートの結果が失敗だった)場合、validate()メソッドはエラーメッセージを表示するためフォームをリビルドし、falseを返します。

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final appTitle = 'Form Validation Demo';

    return MaterialApp(
      title: appTitle,
      home: Scaffold(
        appBar: AppBar(
          title: Text(appTitle),
        ),
        body: MyCustomForm(),
      ),
    );
  }
}

// Create a Form widget.
class MyCustomForm extends StatefulWidget {
  @override
  MyCustomFormState createState() {
    return MyCustomFormState();
  }
}

// Create a corresponding State class.
// This class holds data related to the form.
class MyCustomFormState extends State<MyCustomForm> {
  // Create a global key that uniquely identifies the Form widget
  // and allows validation of the form.
  //
  // Note: This is a GlobalKey<FormState>,
  // not a GlobalKey<MyCustomFormState>.
  final _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    // Build a Form widget using the _formKey created above.
    return Form(
      key: _formKey,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          TextFormField(
            validator: (value) {
              if (value.isEmpty) {
                return 'Please enter some text';
              }
              return null;
            },
          ),
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 16.0),
            child: ElevatedButton(
              onPressed: () {
                // Validate returns true if the form is valid, or false
                // otherwise.
                if (_formKey.currentState.validate()) {
                  // If the form is valid, display a Snackbar.
                  Scaffold.of(context)
                      .showSnackBar(SnackBar(content: Text('Processing Data')));
                }
              },
              child: Text('Submit'),
            ),
          ),
        ],
      ),
    );
  }
}

 

 

 

 

参考

https://flutter.dev/docs/cookbook/forms/validation

コメントを残す

メールアドレスが公開されることはありません。