Flutterで入力形式を自由自在に!Mask TextInputFormatter徹底解説

Mask TextInput Formatterとは?

Flutterアプリ開発において、テキストフィールドへの入力内容を特定の形式に制限したい場面はよくあります。例えば、電話番号の入力欄であれば「XXX-XXX-XXXX」のように、クレジットカード番号であれば「XXXX-XXXX-XXXX-XXXX」のように、定められたフォーマットで入力させたいでしょう。

そのような場合に役立つのが、Mask TextInput Formatterです。

Mask TextInput Formatterは、Flutterのテキストフィールド(TextFieldTextFormField)で使用できる TextInputFormatterの一種で、ユーザーが入力したテキストを指定されたマスク(書式)に従って整形・制限する機能を提供します。

主な特徴

  • 入力フォーマットの統一: ユーザーが入力したテキストを自動的に指定された形式に整形することで、データの統一性を保ち、入力ミスを防ぎます。
  • 入力制限: マスクで指定された文字種(数字、文字など)以外の入力を制限できます。
  • UI/UXの向上: リアルタイムで入力形式を整形することで、ユーザーは正しい形式で入力できているかを確認しやすくなり、快適な入力体験を提供できます。
  • カスタマイズ性: 基本的なマスクだけでなく、正規表現を利用したより複雑なマスクも作成できます。

Mask TextInput Formatterを使用することで、開発者は入力形式に関するロジックをテキストフィールドに直接記述する必要がなくなり、コードの見通しが良くなり、保守性も向上します。また、さまざまなパターンに対応できる柔軟性も備えているため、多くの入力フォームで活用できます。

導入方法

Mask TextInput Formatter を Flutter プロジェクトに導入するには、まず pubspec.yaml ファイルに依存関係を追加する必要があります。

1. pubspec.yaml に依存関係を追加する

dependencies: セクションに以下を追加します。

dependencies:
  flutter:
    sdk: flutter
  mask_text_input_formatter: ^2.6.0 # バージョンは最新のものを確認してください

2. パッケージをインストールする

ターミナルで以下のコマンドを実行し、パッケージをインストールします。

flutter pub get

または、IDE (Visual Studio Code, Android Studio など) の Flutter パッケージ管理機能を使用することもできます。

3. 必要なインポート文を追加する

Dartファイルで MaskTextInputFormatter を使用するには、以下をインポートします。

import 'package:mask_text_input_formatter/mask_text_input_formatter.dart';

これで準備完了です!

Mask TextInput Formatter を使用する準備が整いました。次のステップでは、実際にテキストフィールドにマスクを適用する方法を見ていきましょう。

基本的な使い方:固定長のマスク

Mask TextInput Formatter の最も基本的な使い方は、固定長のマスクを適用することです。これは、入力されるテキストの長さと形式が事前に決まっている場合に有効です。

例:電話番号(XXX-XXX-XXXX)

この例では、電話番号を XXX-XXX-XXXX の形式で入力させたいとします。

1. MaskTextInputFormatter をインスタンス化する

final maskFormatter = MaskTextInputFormatter(
  mask: '###-###-####',
  filter: { "#": RegExp(r'[0-9]') },
  type: MaskAutoCompletionType.lazy
);
  • mask: マスクのパターンを指定します。# は数字を表します。他の文字はそのまま表示されます。
  • filter: 入力可能な文字の種類を制限します。この例では、# に対応する文字として数字(RegExp(r'[0-9]'))のみを許可しています。
  • type: MaskAutoCompletionType.lazy は、入力が完了するまでマスクを適用しないことを意味します。MaskAutoCompletionType.eager を指定すると、入力中もリアルタイムでマスクが適用されます。

2. TextField または TextFormField に適用する

TextField(
  keyboardType: TextInputType.number, // 数字入力に制限
  inputFormatters: [maskFormatter], // MaskTextInputFormatterを適用
)

または、

TextFormField(
  keyboardType: TextInputType.number,
  inputFormatters: [maskFormatter],
  decoration: InputDecoration(
    labelText: '電話番号',
  ),
  validator: (value) {
    if (value == null || value.isEmpty) {
      return '電話番号を入力してください';
    }
    if (value.length != 12) { // ハイフン込みの長さをチェック
      return '電話番号の形式が正しくありません';
    }
    return null;
  },
)
  • inputFormattersmaskFormatter を渡すことで、テキストフィールドへの入力をマスクに従って整形・制限します。
  • keyboardTypeTextInputType.number に設定することで、数字入力に特化したキーボードを表示できます。
  • validatorで入力値の検証を行っています。value.length != 12でマスクされた状態の文字数を含めて検証しています。

動作

ユーザーがテキストフィールドに数字を入力すると、自動的に XXX-XXX-XXXX の形式に整形されます。数字以外の文字を入力しようとすると、入力が拒否されます。

まとめ

この例のように、固定長のマスクを適用することで、ユーザーは定められた形式でしか入力できなくなり、データの統一性と正確性を確保できます。

応用編:可変長のマスク

固定長のマスクは便利な一方で、入力されるテキストの長さが固定されていない場合、つまり可変長の場合には対応できません。例えば、郵便番号の入力欄で、3桁-4桁の形式だけでなく、7桁の数字のみの入力も許可したい場合などが考えられます。

Mask TextInput Formatter では、このような可変長のマスクも実現可能です。正規表現を組み合わせることで、より柔軟な入力形式に対応できます。

例:郵便番号(XXX-XXXX または XXXXXXX)

この例では、郵便番号を XXX-XXXX の形式、または XXXXXXX の形式で入力させたいとします。

1. MaskTextInputFormatter をインスタンス化する

final maskFormatter = MaskTextInputFormatter(
  mask: '###-####',
  filter: { "#": RegExp(r'[0-9]') },
  type: MaskAutoCompletionType.lazy,
  initialText: '',
  maskAutoCompletion: true
);

この設定では、初期設定として ###-#### が適用されます。 ユーザーが7桁の数字を続けて入力すると、自動的にマスクが解除され、7桁の数字がそのまま表示されるように実装していきます。 maskAutoCompletion: trueに設定することで入力文字数がマスクの長さに満たない場合に自動補完します。

2. TextField または TextFormField に適用する

TextFormField(
  keyboardType: TextInputType.number,
  inputFormatters: [maskFormatter],
  decoration: InputDecoration(
    labelText: '郵便番号',
  ),
  validator: (value) {
    if (value == null || value.isEmpty) {
      return '郵便番号を入力してください';
    }
    if (value.length != 8 && value.length != 7) {
        return '郵便番号の形式が正しくありません';
    }
     if (value.length == 8 && !RegExp(r'^\d{3}-\d{4}$').hasMatch(value)){
         return '郵便番号の形式が正しくありません';
     }
     if (value.length == 7 && !RegExp(r'^\d{7}$').hasMatch(value)){
         return '郵便番号の形式が正しくありません';
     }


    return null;
  },
)

解説

  • value.length != 8 && value.length != 7 : 入力された文字数が8文字(XXX-XXXX)でも7文字(XXXXXXX)ない場合はエラーを表示
  • RegExp(r'^\d{3}-\d{4}$'): 正規表現でXXX-XXXXの形式をチェックします。
  • RegExp(r'^\d{7}$'): 正規表現でXXXXXXXの形式をチェックします。
  • validatorで入力値の検証を行うことで可変長の入力を適切にチェックします。

動作

ユーザーがテキストフィールドに数字を入力すると、初期状態では XXX-XXXX の形式で整形されます。しかし、7桁の数字が連続して入力されると、マスクは適用されず、XXXXXXX の形式で表示されます。

まとめ

正規表現と Mask TextInput Formatter を組み合わせることで、より柔軟な入力形式に対応できます。可変長のマスクを適用することで、さまざまな入力パターンに対応できる、よりユーザーフレンドリーなUIを実現できます。

カスタムマスクの作成

Mask TextInput Formatter には、あらかじめ定義されたマスクだけでなく、独自のマスクを定義する機能も備わっています。これにより、特定の要件に合わせた、より複雑な入力形式に対応できます。

カスタムマスクの定義方法

カスタムマスクを定義するには、filter パラメータで、マスクで使用する文字と、それに対応する正規表現を定義します。

例:特定の文字と数字の組み合わせ(A#A-#A#)

この例では、A はアルファベット、# は数字を表すカスタムマスク A#A-#A# を作成します。

1. MaskTextInputFormatter をインスタンス化する

final maskFormatter = MaskTextInputFormatter(
  mask: 'A#A-#A#',
  filter: {
    "A": RegExp(r'[a-zA-Z]'),
    "#": RegExp(r'[0-9]')
  },
  type: MaskAutoCompletionType.lazy
);
  • filter:

    • "A": RegExp(r'[a-zA-Z]'): A に対応する文字として、アルファベット(大文字・小文字)を許可します。
    • "#": RegExp(r'[0-9]'): # に対応する文字として、数字を許可します。

2. TextField または TextFormField に適用する

TextField(
  inputFormatters: [maskFormatter],
)

動作

ユーザーがテキストフィールドに入力すると、A#A-#A# の形式に従って入力が制限されます。アルファベットと数字以外の文字を入力しようとすると、入力が拒否されます。

より複雑なカスタムマスクの例:

例えば、特定のパターンに合致する文字列のみ許可したい場合は、より複雑な正規表現を使用できます。

final maskFormatter = MaskTextInputFormatter(
  mask: 'ABC-###-XYZ',
  filter: {
    "A": RegExp(r'[A-Z]'),
    "B": RegExp(r'[A-Z]'),
    "C": RegExp(r'[A-Z]'),
    "#": RegExp(r'[0-9]'),
    "X": RegExp(r'[A-Z]'),
    "Y": RegExp(r'[A-Z]'),
    "Z": RegExp(r'[A-Z]'),
  },
  type: MaskAutoCompletionType.lazy
);

この例では、ABC-###-XYZ という形式で、ABCXYZ は大文字のアルファベット、### は数字である必要があります。

まとめ

カスタムマスクを作成することで、Mask TextInput Formatter の適用範囲を大幅に広げることができます。特定の要件に合わせた、より高度な入力形式の制御が可能になります。正規表現の知識を活用することで、非常に複雑なマスクも定義できます。

実践例:電話番号、クレジットカード番号

ここでは、Mask TextInput Formatter を使用した、より具体的な実践例として、電話番号とクレジットカード番号の入力フォームを作成します。

1. 電話番号の入力フォーム(XXX-XXX-XXXX)

前の例でも触れましたが、電話番号の入力は Mask TextInput Formatter の基本的な使用例です。

import 'package:flutter/material.dart';
import 'package:mask_text_input_formatter/mask_text_input_formatter.dart';

class PhoneNumberInput extends StatelessWidget {
  final maskFormatter = MaskTextInputFormatter(
      mask: '###-###-####',
      filter: { "#": RegExp(r'[0-9]') },
      type: MaskAutoCompletionType.lazy
  );

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(16.0),
      child: TextFormField(
        keyboardType: TextInputType.number,
        inputFormatters: [maskFormatter],
        decoration: InputDecoration(
          labelText: '電話番号',
          border: OutlineInputBorder(),
        ),
        validator: (value) {
          if (value == null || value.isEmpty) {
            return '電話番号を入力してください';
          }
          if (value.length != 12) { // ハイフン込みの長さをチェック
            return '電話番号の形式が正しくありません';
          }
          return null;
        },
      ),
    );
  }
}

ポイント

  • keyboardType: TextInputType.number: 数字入力に最適化されたキーボードを表示します。
  • validator: 入力値の検証を行います。必須入力と、電話番号の形式が正しいかをチェックします。

2. クレジットカード番号の入力フォーム(XXXX-XXXX-XXXX-XXXX)

クレジットカード番号は、より厳格な形式が求められるため、Mask TextInput Formatter を活用する価値があります。

import 'package:flutter/material.dart';
import 'package:mask_text_input_formatter/mask_text_input_formatter.dart';

class CreditCardNumberInput extends StatelessWidget {
  final maskFormatter = MaskTextInputFormatter(
      mask: '####-####-####-####',
      filter: { "#": RegExp(r'[0-9]') },
      type: MaskAutoCompletionType.lazy
  );

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(16.0),
      child: TextFormField(
        keyboardType: TextInputType.number,
        inputFormatters: [maskFormatter],
        decoration: InputDecoration(
          labelText: 'クレジットカード番号',
          border: OutlineInputBorder(),
        ),
        validator: (value) {
          if (value == null || value.isEmpty) {
            return 'クレジットカード番号を入力してください';
          }
          if (value.length != 19) { // ハイフン込みの長さをチェック
            return 'クレジットカード番号の形式が正しくありません';
          }
          // より厳格なチェックが必要な場合は、Luhnアルゴリズムなどを実装する
          return null;
        },
      ),
    );
  }
}

ポイント

  • mask: '####-####-####-####': クレジットカード番号の形式に合わせてマスクを設定します。
  • validator: 入力値の検証を行います。必須入力と、クレジットカード番号の形式が正しいかをチェックします。
  • Luhnアルゴリズム: クレジットカード番号の有効性を検証するためのLuhnアルゴリズム(Mod 10)を実装することで、さらに厳格なチェックを行うことができます。これは、この例では省略されていますが、セキュリティを考慮する場合は実装を検討してください。

補足:

実際のクレジットカード番号の入力フォームでは、カードブランドの判別や、有効期限、セキュリティコードの入力欄なども必要になります。Mask TextInput Formatter は、これらの要素と組み合わせて使用することで、より高度な入力フォームを作成できます。

まとめ

これらの例からわかるように、Mask TextInput Formatter は、電話番号やクレジットカード番号など、特定の形式での入力が求められる場合に非常に有効です。適切なマスクとバリデーションを組み合わせることで、ユーザーエクスペリエンスを向上させ、データの品質を確保できます。

エラー処理とバリデーション

Mask TextInput Formatter は入力されたテキストを指定された形式に整形・制限する強力なツールですが、それだけでは万全ではありません。ユーザーが誤った形式で入力した場合や、必須項目が未入力の場合など、エラーが発生する可能性は常にあります。

そのため、Mask TextInput Formatter を使用する際には、適切なエラー処理とバリデーションを実装することが非常に重要です。

1. validator を使用した基本的なバリデーション

すでに前の例でも示しましたが、TextFormFieldvalidator プロパティを使用することで、入力された値に対して基本的な検証を行うことができます。

TextFormField(
  // ...
  validator: (value) {
    if (value == null || value.isEmpty) {
      return '必須項目です'; // 未入力エラー
    }
    if (value.length != 12) {
      return '形式が正しくありません'; // 形式エラー
    }
    return null; // エラーなし
  },
)
  • 必須項目のチェック: value == null || value.isEmpty で、フィールドが空かどうかをチェックします。
  • 形式のチェック: value.length や正規表現を使用して、入力されたテキストが正しい形式かどうかをチェックします。
  • エラーメッセージの表示: バリデーションに失敗した場合、適切なエラーメッセージを返します。このメッセージは、TextFormField の下に表示されます。

2. カスタムバリデーション

より複雑なバリデーションが必要な場合は、カスタムのバリデーション関数を作成できます。例えば、電話番号の市外局番が特定の地域のものであるかどうかをチェックする場合などが考えられます。

String? validatePhoneNumber(String? value) {
  if (value == null || value.isEmpty) {
    return '電話番号を入力してください';
  }

  if (!RegExp(r'^(03|06|052)-\d{4}-\d{4}$').hasMatch(value)) {
    return '市外局番が正しくありません';
  }

  return null;
}

TextFormField(
  // ...
  validator: validatePhoneNumber,
)

3. Form ウィジェットの使用

複数の入力フィールドがある場合は、Form ウィジェットを使用することで、バリデーションをより効率的に管理できます。

final _formKey = GlobalKey<FormState>();

Form(
  key: _formKey,
  child: Column(
    children: [
      TextFormField(
        // ...
        validator: (value) {
          // ...
        },
      ),
      TextFormField(
        // ...
        validator: (value) {
          // ...
        },
      ),
      ElevatedButton(
        onPressed: () {
          if (_formKey.currentState!.validate()) {
            // バリデーション成功時の処理
          }
        },
        child: Text('送信'),
      ),
    ],
  ),
)
  • GlobalKey<FormState> を作成し、Form ウィジェットに割り当てます。
  • _formKey.currentState!.validate() を呼び出すことで、すべての TextFormFieldvalidator が実行されます。
  • validate()true を返した場合、すべてのバリデーションが成功したことを意味します。

4. エラーハンドリング

バリデーションエラーが発生した場合、ユーザーに分かりやすいエラーメッセージを表示することが重要です。TextFormFielddecoration プロパティを使用して、エラーメッセージを表示したり、入力フィールドのスタイルを変更したりすることができます。

5. 非同期バリデーション

API 呼び出しなど、時間のかかるバリデーション処理が必要な場合は、非同期バリデーションを検討してください。

まとめ

Mask TextInput Formatter は、入力フォームの品質を高める上で非常に役立ちますが、適切なエラー処理とバリデーションを組み合わせることで、より堅牢で使いやすいアプリケーションを開発できます。ユーザーエクスペリエンスを向上させるために、これらの要素を忘れずに実装しましょう。

まとめ:Mask TextInput Formatterでより快適なUIを

Mask TextInput Formatter は、Flutterアプリ開発において、テキストフィールドへの入力体験を向上させるための強力なツールです。この記事では、その基本的な使い方から応用的なテクニック、そしてエラー処理とバリデーションまで、幅広く解説しました。

Mask TextInput Formatter を導入するメリット

  • 入力フォーマットの統一: ユーザーは指定された形式でしか入力できないため、データの統一性が保たれ、入力ミスを防ぐことができます。
  • UI/UXの向上: リアルタイムで入力形式が整形されるため、ユーザーは正しい形式で入力できているかを確認しやすくなり、快適な入力体験が得られます。
  • 開発効率の向上: 入力形式に関するロジックをテキストフィールドに直接記述する必要がなくなり、コードの見通しが良くなり、保守性も向上します。
  • 柔軟なカスタマイズ: 基本的なマスクだけでなく、正規表現を利用したより複雑なマスクも作成できるため、さまざまな入力フォームに対応できます。

より快適なUIのために

Mask TextInput Formatter を最大限に活用するためには、以下の点に注意しましょう。

  • 適切なマスクの選択: 入力されるデータの形式に合わせて、最適なマスクを選択します。固定長、可変長、カスタムマスクなど、さまざまな選択肢があります。
  • 丁寧なエラー処理とバリデーション: ユーザーが誤った形式で入力した場合に備えて、適切なエラーメッセージを表示し、バリデーションを行うことで、データの品質を確保します。
  • アクセシビリティへの配慮: スクリーンリーダーを使用するユーザーのために、適切なラベルやヒントを提供することで、アクセシビリティを向上させます。

最後に

Mask TextInput Formatter は、Flutterアプリの入力フォームをより洗練されたものにするための強力な武器です。この記事で紹介した内容を参考に、積極的に活用し、ユーザーにとってより快適なUIを実現してください。

コメントを残す