🐙

Flutter TextFormFieldのカスタムinputFormatters @初心者

2024/12/03に公開

TextFormFieldのカスタムinputFormatters

TextFormFieldのinputFormattersをつかって下記の様に文字数制限をしてました。

/// 文字数 12文字まで
inputFormatters: [
                 LengthLimitingTextInputFormatter(12),
              ],

ただ、こちらだと半角の場合認識されず12文字以上入力できてしまう状態になりました。
ぐぬぬしていて出来なかったので他を参考にカスタムinputFormattersを作成することにしました。

カスタムinputFormattersを作成

今回作成したのが下記カスタムinputFormattersになります。
全角だろうが、半角だろうが12文字以上は入力できないようにしています。

/// カスタムの文字数フォーマッター
class CustomInputFormatter extends TextInputFormatter {
  /// コンストラクタ
  CustomInputFormatter(this.maxLength);

  /// 長さ
  final int maxLength;

  /// 半角
  final RegExp halfRegExp = RegExp(r'[\u0020-\u007E\uFF61-\uFF9F]');
  
  TextEditingValue formatEditUpdate(
    TextEditingValue oldValue,
    TextEditingValue newValue,
  ) {
    final text = newValue.text;
    var total = 0;
    var index = 0;

    // 12文字以内のリスト作成
    final charsList = <String>[];

    // whileでチェック
    while (index < text.length && total < maxLength) {
      final char = text[index];

      /// 全角、半角でも一文字とする
      final length = halfRegExp.hasMatch(char) ? 1 : 1;

      // 全体の長さ
      total += length;

      if (total > maxLength) {
        // 12文字以上break
        break;
      }

      /// 全部リストに入れる
      charsList.add(char);
      index++;
    }

    /// 配列を文字列
    final newText = charsList.join();

    // テキストが変更された場合、新しい値を返す
    if (newText != newValue.text) {
      return TextEditingValue(
        text: newText,
        selection: TextSelection.collapsed(offset: newText.length),
      );
    }

    return newValue;
  }
}

まず半角はどこから?

まずこちらの企業様の記事を参照させてもらいました。
https://www.k-intl.co.jp/blog/B_220831A

記事内に、'[\u0020-\u007E\uFF61-\uFF9F]'が半角(数字も含む)と記載あったのでこちらから調べました。

カスタムinputFormatters作成方法

こちらの記事を参考にしました。いろんな所から情報収集!

https://qiita.com/kazuhideoki/items/17ed342026c0da2bed4c

https://zenn.dev/mkikuchi/articles/c94957d7622c55

https://flutter.salon/widget/textinputformatter/

コード説明

まずはクラス宣言。TextInputFormatterを継承したクラスを宣言します。

class CustomInputFormatter extends TextInputFormatter {

正規表現

こちらで文字列の半角判断するための正規表現を使用します。

 final RegExp halfRegExp = RegExp(r'[\u0020-\u007E\uFF61-\uFF9F]');

TextEditingValue

ユーザーがテキスト入力または削除するたびに表示されます。


TextEditingValue formatEditUpdate(
  TextEditingValue oldValue,
  TextEditingValue newValue,
) {

oldValue:変更前のテキスト
newValue:変更後のテキスト

while文で一文字ずつチェック

    while (index < text.length && total < maxLength) {
      final char = text[index];

      /// 全角、半角でも一文字とする
      final length = halfRegExp.hasMatch(char) ? 1 : 1;

      // 全体の長さ
      total += length;

      if (total > maxLength) {
        // 12文字以上break
        break;
      }

      /// 全部リストに入れる
      charsList.add(char);
      index++;
    }

テキストの返却

if (newText != newValue.text) {
  return TextEditingValue(
    text: newText,
    selection: TextSelection.collapsed(offset: newText.length),
  );
}
return newValue;

newTextとnewValue.textが異なる場合、テキストを更新します。
更新して新しいTextEditingValueを返す処理になります。

text: 更新されたテキスト
selection: カーソルの位置をテキストの末尾に設定します。

変更がない場合は、元のnewValueをそのまま返します。

TextEditingValueとは?

TextEditingValueは、Flutterでテキスト入力フィールドの状態を表すクラスです。このクラスは以下の情報を持っています。

text:現在のテキスト内容
selection:テキスト内の選択範囲(カーソルの位置や選択されているテキストの範囲)

このメソッドは、新しいTextEditingValueを返すことで、テキストフィールドの内容を更新します。

使い方

TextField(
  inputFormatters: [
    CustomInputFormatter(12), /// 制限したい文字数を渡す。
  ],
),

以上でカスタムinputFormatters の作成終わりです。
初めて作成しましたが、よくできたかなと思います。

ただ、backend側で処理するのが通例とのことなので、出来るならサーバー側で処理しましょう。
以上。

Discussion