【Flutter】思い通りのバリデーションを作ろう
この記事は、Flutter大学アドベントカレンダー2022 13日目の記事です。
はじめに
はじめまして、ヤスーです。
普段はメディア系のSIer、趣味でFlutterアプリ開発を行なっています。
今回はform_field_validatorのパッケージと正規表現を利用してカスタムバリデーション(入力フォームのチェック処理)の実装を記事にしてみました。
最近、入力フォームの実装で、名前の「必須入力チェック」と「文字数チェック」の組み合わせや、インスタグラムの「URLフォーマットチェック(正規表現でのチェック)」等Flutterでバリデーションを開発する機会があったので、その時の方法を載せてみてます。
サンプルコードは以下に格納していますので、ぜひこちらも合わせて参考にしていただけると幸いです。
目次
- パッケージのインストール
- カスタムバリデーションの実装
- 入力フォーム画面での利用
1. パッケージのインストール
カスタムバリデーションを作成するためのパッケージをインストールしていきます。
Flutterプロジェクトのpubspec.yamlに、form_field_validatorを追加してpub get
します。
dependencies:
flutter:
sdk: flutter
+ form_field_validator: ^1.1.0
2. カスタムバリデーションの実装
今回は以下のバリデーションを実装していきます。
2.1 名前入力のバリデータ
- 必須入力チェック
- 最大長チェック
2.2 正規表現によるインスタグラムのURL入力規則のバリデータ
- 無効な文字チェック
- URLのチェック
2.1 名前入力のバリデータ
名前入力時に未入力の場合と5文字を超えた場合に、バリデーションのチェックエラーが表示される実装を行います。
名前入力用バリデータの変数準備
form_field_validatorのパッケージを利用して簡単に実装ができます。
まず、validators.dart
というファイルを作成して、そこへnameValidator
という変数名で以下のように定義します。
import 'package:form_field_validator/form_field_validator.dart';
final nameValidator = MultiValidator([]);
MultiValidator
は、複数のバリデータ(入力チェック処理)をリストで纏めます。
必須入力チェック
MultiValidator
のリストに必須入力チェックのバリデータを追加します。
import 'package:form_field_validator/form_field_validator.dart';
final nameValidator = MultiValidator([
+ // 必須入力チェック
+ RequiredValidator(errorText: "名前を入力してください"),
]);
RequiredValidator
は入力必須チェックのバリデーションで、1つ目の引数errorText
には入力チェックエラー時に表示する文字列を記述しています。
最大長チェック
MultiValidator
のリストに最大長チェック用のバリデータを追加します。
import 'package:form_field_validator/form_field_validator.dart';
final nameValidator = MultiValidator([
// 必須入力チェック
RequiredValidator(errorText: "名前を入力してください"),
+ // 最大長チェック
+ MaxLengthValidator(5,errorText: "名前は5文字以内で入力してください")
]);
MaxLengthValidator
は最大長チェックのバリデーションになっています。1つ目の引数には最大長の数字、2つ目の引数errorText
にはチェックエラー時に表示する文字列を記述しています。
2.2 SNSのURL入力バリデーション
自分のInstagramのURLに無効な文字が含まれている場合と、InstagramのURLフォーマットに従っていない場合に、バリデーションのチェックエラーが表示される実装を行います。
InstagramのURL入力用バリデータの変数準備
validators.dart
にinstagramValidator
の変数を追記します。
+ final instagramValidator = MultiValidator([]);
無効な文字のチェック
SNSのURL内に無効な文字列が含まれていないか(半角英数字+記号のみの入力制限)をチェックするバリデータを作成する。
url_validator.dart
という新しいファイルに以下の定義をする。
import 'package:form_field_validator/form_field_validator.dart';
class UrlValidator extends TextFieldValidator {
UrlValidator({required String errorText}) : super(errorText);
bool isValid(String? value) =>
RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9./:!#$%&'*+-=?^_`{|}~]+$").hasMatch(value!);
}
validators.dart
に作成したバリデータを追加します。
+ import 'package:custom_validator/validator/sns_url_character_validator.dart';
final instagramValidator = MultiValidator([
+ UrlValidator(errorText: "URLに無効な文字が含まれています"),
]);
InstagramのURLチェック
InstagramのアカウントURLは「https://www.instagram.com/ユーザー名」
となっています。そのため、URLフォーマットを正規表現でチェックするバリデータを作成します。
instagram_url_validator.dart
を作成して以下を記述します。
import 'package:form_field_validator/form_field_validator.dart';
/// InstagramのURLであることを確認するValidator
class InstagramUrlValidator extends TextFieldValidator {
InstagramUrlValidator({required String errorText}) : super(errorText);
bool isValid(String? value) => RegExp(
r"^https?://www\.instagram\.com/[a-zA-Z0-9.a-zA-Z0-9./:!#$%&'*+-=?^_`{|}~]+$")
.hasMatch(value!);
}
validators.dart
に作成したバリデータを追加します。
import 'package:custom_validator/validator/sns_url_character_validator.dart';
+ import 'package:custom_validator/validator/instagram_url_validator.dart';
final instagramValidator = MultiValidator([
UrlValidator(errorText: "URLに無効な文字が含まれています"),
+ InstagramUrlValidator(errorText: "Instagramの正しいURLを入力してください(https://www.instagram.com/ユーザー名)")
]);
3. 入力フォーム画面での利用
画面ソースにおけるバリデータの設定手順は以下の通りになります。
-
TextFormField
のvalidator
引数に目次 2.カスタムバリデータの実装で実装したnameValidator
やinstagramValidator
を設定する。 -
Form
クラスで1.の入力フォーム等のウィジェットを囲う - 決定ボタン押下時等にValidatorが動くよう
key.currentState!.validate()
の処理を記述する。
まずは、ソースコードを載せます。
import 'package:custom_validator/success.dart';
import 'package:custom_validator/validators/custom_validators.dart';
import 'package:flutter/material.dart';
class FormFieldWidget extends StatefulWidget {
const FormFieldWidget({Key? key}) : super(key: key);
_FormFieldWidgetState createState() => _FormFieldWidgetState();
}
class _FormFieldWidgetState extends State<FormFieldWidget> {
Widget build(BuildContext context) {
const key = GlobalObjectKey<FormState>('FORM_KEY');
/// ユーザー名のTextEditingController
TextEditingController userNameController = TextEditingController();
/// インスタグラムURLのTextEditingController
TextEditingController instagramUrlController = TextEditingController();
return Form(
key: key,
child: Padding(
padding: const EdgeInsets.all(15.0),
child: Column(
children: [
/// 名前のテキストフォーム
const Text('ユーザー名 '),
TextFormField(
controller: userNameController,
validator: nameValidator,
decoration: const InputDecoration(
errorMaxLines: 3,
),
),
const SizedBox(height: 30),
/// インスタグラムURLの入力フォーム
const Text('インスタグラムのURL'),
TextFormField(
controller: instagramUrlController,
validator: instagramValidator,
decoration: const InputDecoration(
errorMaxLines: 3,
),
),
const SizedBox(height: 30),
/// 決定ボタン
MaterialButton(
onPressed: () {
if (key.currentState!.validate()) {
// フォームの入力値が正しかった場合成功画面に遷移する。
Navigator.push(context,
MaterialPageRoute(builder: (context) => const SuccessScreen())
);
}
},
child: const Text(
'決定',
),
),
],
),
),
);
}
}
TextFormField
で入力フォームを用意して、validator
の引数に作成したカスタムバリデータを設定する。
1. 名前入力用のフォームとインスタグラムURL入力用のフォームを用意する。
import 'package:custom_validator/validators/custom_validators.dart';
const Text('ユーザー名'),
TextFormField(
controller: userNameController,
// 上記で作成したnameValidatorを挿入
validator: nameValidator
decoration: const InputDecoration(
errorMaxLines: 3,
),
),
import 'package:custom_validator/validators/custom_validators.dart';
/// インスタグラムのURL入力フォーム
const Text('インスタグラムのURL'),
TextFormField(
controller: userNameController,
// 上記で作成したinstagramValidatorを挿入
validator: instagramValidator,
decoration: const InputDecoration(
errorMaxLines: 3,
),
),
Form
クラスで入力フォームのウィジェット等を囲う
2. const key = GlobalObjectKey<FormState>('FORM_KEY');
Form(key: key,
child: //※入力フォーム等のウィジェット(ソースが長いため省略)
)
key.currentState!.validate()
の処理を記述する。
3. 決定ボタン押下時等にValidatorが動くよう/// 決定ボタン
MaterialButton(
onPressed: () {
if (key.currentState!.validate()) {
// フォームの入力値が正しかった場合成功画面に遷移する。
Navigator.push(context,
MaterialPageRoute(builder: (context) => const SuccessScreen())
);
}
},
child: const Text('OK',),
),
おわりに
今回は、カスタムバリデータの実装方法について紹介していきました。
紹介した方法は、自分でカスタムできることに加えて、バリデータの使い回しなどもできることが利点だと思っています。
参考
Discussion