How to add a mask in a TextField in Flutter?

37,899

Solution 1

I modified some things and managed to get the expected result.

I created this class to define the variable

static final _UsNumberTextInputFormatter _birthDate = new _UsNumberTextInputFormatter();

class _UsNumberTextInputFormatter extends TextInputFormatter {
  @override
  TextEditingValue formatEditUpdate(
TextEditingValue oldValue,
TextEditingValue newValue  ) {
final int newTextLength = newValue.text.length;
int selectionIndex = newValue.selection.end;
int usedSubstringIndex = 0;
final StringBuffer newText = new StringBuffer();
if (newTextLength >= 3) {
  newText.write(newValue.text.substring(0, usedSubstringIndex = 2) + '/');
  if (newValue.selection.end >= 2)
    selectionIndex ++;
}
if (newTextLength >= 5) {
  newText.write(newValue.text.substring(2, usedSubstringIndex = 4) + '/');
  if (newValue.selection.end >= 4)
    selectionIndex++;
}
if (newTextLength >= 9) {
  newText.write(newValue.text.substring(4, usedSubstringIndex = 8));
  if (newValue.selection.end >= 8)
    selectionIndex++;
}
// Dump the rest.
if (newTextLength >= usedSubstringIndex)
  newText.write(newValue.text.substring(usedSubstringIndex));
return new TextEditingValue(
  text: newText.toString(),
  selection: new TextSelection.collapsed(offset: selectionIndex),
); 
} 
}

And finally I added an inputformat to the textfield

new TextFormField( 
          maxLength: 10,
          keyboardType: TextInputType.datetime, 
          validator: _validateDate,
          decoration: const InputDecoration(
            hintText: 'Digite sua data de nascimento',
            labelText: 'Data de Nascimento',
          ),
          inputFormatters: <TextInputFormatter> [
                WhitelistingTextInputFormatter.digitsOnly,
                // Fit the validating format.
                _birthDate,
              ]
        ),

Now it's all right, thank you

Solution 2

https://pub.dartlang.org/packages/masked_text

masked_text

A package for masked texts, so if you want a mask for phone, or zip code or any kind of mask, just use it :D

Getting Started

It's very simple, it's a Widget as all the other ones.

new MaskedTextField
(
    maskedTextFieldController: _textCPFController,
    mask: "xx/xx/xxxx",
    maxLength: 10,
    keyboardType: TextInputType.number,
    inputDecoration: new InputDecoration(
    hintText: "Digite a data do seu nascimento", labelText: "Data"),
);

'x' is the normal char that your text will have.

this sample reproduces something like this in the end: 11/02/1995.

Solution 3

My solution:

class MaskTextInputFormatter extends TextInputFormatter {
  final int maskLength;
  final Map<String, List<int>> separatorBoundries;

  MaskTextInputFormatter({
    String mask = "xx.xx.xx-xxx.xx",
    List<String> separators = const [".", "-"],
  })  : this.separatorBoundries = {
          for (var v in separators)
            v: mask.split("").asMap().entries.where((entry) => entry.value == v).map((e) => e.key).toList()
        },
        this.maskLength = mask.length;

  @override
  TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
    final int newTextLength = newValue.text.length;
    final int oldTextLength = oldValue.text.length;
    // removed char
    if (newTextLength < oldTextLength) return newValue;
    // maximum amount of chars
    if (oldTextLength == maskLength) return oldValue;

    // masking
    final StringBuffer newText = StringBuffer();
    int selectionIndex = newValue.selection.end;

    // extra boundaries check
    final separatorEntry1 = separatorBoundries.entries.firstWhereOrNull((entry) => entry.value.contains(oldTextLength));
    if (separatorEntry1 != null) {
      newText.write(oldValue.text + separatorEntry1.key);
      selectionIndex++;
    } else {
      newText.write(oldValue.text);
    }
    // write the char
    newText.write(newValue.text[newValue.text.length - 1]);

    return TextEditingValue(
      text: newText.toString(),
      selection: TextSelection.collapsed(offset: selectionIndex),
    );
  }
}
Share:
37,899
Victor Henrique
Author by

Victor Henrique

Updated on July 09, 2022

Comments

  • Victor Henrique
    Victor Henrique almost 2 years

    I'm trying to add a date mask to a textField since I did not like the Date Picker because for date of birth, for example, it is not as nimble. After that, converting from string to datetime, I believe I can continue the project, Thanks in advance.

    static final TextEditingController _birthDate = new TextEditingController();
        new TextFormField( 
                controller: _birthDate, 
                maxLength: 10,
                keyboardType: TextInputType.datetime, 
                validator: _validateDate
            ), String _validateDate(String value) { 
        if(value.isEmpty)
            return null;
        if(value.length != 10)
            return 'Enter date in DD / MM / YYYY format';
        return null; 
    }
    
  • Hardy
    Hardy over 4 years
    it is just going into infinite loop that library is unfortunately not working.
  • Renan Coelho
    Renan Coelho over 4 years
    don't use this. here is a better approach using the native TextField widget: pub.dev/packages/mask_text_input_formatter
  • TootsieRockNRoll
    TootsieRockNRoll over 4 years
    @RenanCoelho do you update the text manually later on and keep the format?