Kevin Zhang
Kevin Zhang

Reputation: 1082

How to implement a text mask in Flutter

As described in the title, how to implement text mask in Flutter.

I am just writing a one below but not that suitable, since it can't display the mask to the user when typing, for example, when the text mask is 'MM/HH', if we do not display the slash during the user's typing, the user will typing the slash '/' themself, as they do not know the slash will auto-fill the input. There is a example here that can explain what am I said (It's a web implementation, not Flutter), so how to implement the mask-like in this link in Flutter?

This is my current implementation.

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

class MaskedTextInputFormatter extends TextInputFormatter {
  final String mask;
  final String separator;

  MaskedTextInputFormatter({
    @required this.mask,
    @required this.separator,
  }) {
    assert(mask != null);
    assert(separator != null);
  }

  @override
  TextEditingValue formatEditUpdate(
      TextEditingValue oldValue, TextEditingValue newValue) {
    if (newValue.text.length > 0) {
      if (newValue.text.length > oldValue.text.length) {
        if (newValue.text.length > mask.length) return oldValue;
        if (newValue.text.length < mask.length &&
            mask[newValue.text.length - 1] == separator) {
          return TextEditingValue(
            text:
                '${oldValue.text}$separator${newValue.text.substring(newValue.text.length - 1)}',
            selection: TextSelection.collapsed(
              offset: newValue.selection.end + 1,
            ),
          );
        }
      }
    }
    return newValue;
  }
}

Any help are appreciated!

PS: I searched a Flutter package mask_text_input_formatter, seems it also can't display the mask when typing, see issue.

Upvotes: 9

Views: 11488

Answers (1)

kishan vekariya
kishan vekariya

Reputation: 471

try by adding extra condition for modifying text value

  1. add 1 extra condition.

    import 'package:flutter/material.dart';
    import 'package:flutter/services.dart';
    
    class MaskedTextInputFormatter extends TextInputFormatter {
      final String mask;
      final String separator;
    
      MaskedTextInputFormatter({
        @required this.mask,
        @required this.separator,
      }) {
        assert(mask != null);
        assert(separator != null);
      }
    
      @override
      TextEditingValue formatEditUpdate(
          TextEditingValue oldValue, TextEditingValue newValue) {
        if (newValue.text.length > 0) {
          if (newValue.text.length > oldValue.text.length) {
            if (newValue.text.length > mask.length) return oldValue;
            if (newValue.text.length < mask.length &&
                mask[newValue.text.length - 1] == separator &&
                newValue.text.substring(newValue.text.length - 1) != separator) {
              return TextEditingValue(
                text:
                    '${oldValue.text}$separator${newValue.text.substring(newValue.text.length - 1)}',
                selection: TextSelection.collapsed(
                  offset: newValue.selection.end + 1,
                ),
              );
            }
          }
        }
        return newValue;
      }
    }

  2. by using regex depending your need.

      FilteringTextInputFormatter(r"[A-za-z][A-Za-z]\/[A-za-z][A-Za-z]", allow: false);
    

OR

     FilteringTextInputFormatter(r"[A-za-z0-9][A-Za-z0-9]\/[A-za-z0-9][A-Za-z0-9]", allow: false);

example as below allow parameter is for if you want to allow particular pattern to be accepted or not

Textfield(
  label: "CardNumber",
  hint: "CardNumber",
  focusNode: cardNumberFocus,
  textInputFormatter: [
    MaskedTextInputFormatter(mask: 'xxxx xxxx xxxx xxxx', separator: ' '),
    FilteringTextInputFormatter(r"[A-za-z0-9][A-Za-z0-9]\/[A-za-z0-9][A-Za-z0-9]", allow: true);
  ],
);

Upvotes: 2

Related Questions