How to: add a blank space after every 4 characters when typing in TextFormField

Viewed 5262

I'm trying to find a way to add a blank space while typing in a TextFormField.

I found a way how to do this a while back but I cannot find it now, no matter what I search for on Google or here on StackOverflow ..

Basically I want to turn the text shown in the textfield from 000011112222333 to 0000 1111 2222 3333

I'm guessing I need to use some RegExp check in the onChanged function of a TextFormField and use it to change the TextEditingController's .text

3 Answers

I also faced this problem before and luckily found a way to do this somewhere. First create a class that extends TextInputFormatter

customInputFormatter.dart

class CustomInputFormatter extends TextInputFormatter {
  @override
  TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
    var text = newValue.text;

    if (newValue.selection.baseOffset == 0) {
      return newValue;
    }

    var buffer = new StringBuffer();
    for (int i = 0; i < text.length; i++) {
      buffer.write(text[i]);
      var nonZeroIndex = i + 1;
      if (nonZeroIndex % 4 == 0 && nonZeroIndex != text.length) {
        buffer.write(' '); // Replace this with anything you want to put after each 4 numbers
      }
    }

    var string = buffer.toString();
    return newValue.copyWith(
        text: string,
        selection: new TextSelection.collapsed(offset: string.length)
    );
  }
}

And then add it to the list of inputFormatters[] of TextFormField

inputFormatters: [
   FilteringTextInputFormatter.digitsOnly,
   new CustomInputFormatter()
],   

Inspired from Dung Ngo's Code

I added cursor tracking so when the user erases from the the TextFormField the cursor doesn't goes back to the beginning of field.

I commented the WhitelistingTextInputFormatter.digitsOnly / FilteringTextInputFormatter.digitsOnly in my pen since I used regular expressions.

Here's the pen https://codepen.io/brocatz/pen/dyNOqVy

@override
TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
    var text = newValue.text;
    text = text.replaceAll(RegExp(r'(\s)|(\D)'), '');

    int offset = newValue.selection.start;
    var subText =
        newValue.text.substring(0, offset).replaceAll(RegExp(r'(\s)|(\D)'), '');
    int realTrimOffset = subText.length;

    // if (newValue.selection.baseOffset == 0) {
    //   return newValue;
    // }

    var buffer = new StringBuffer();
    for (int i = 0; i < text.length; i++) {
      buffer.write(text[i]);
      var nonZeroIndex = i + 1;
      if (nonZeroIndex % 4 == 0 && nonZeroIndex != text.length) {
        buffer.write(
            ' '); // Replace this with anything you want to put after each 4 numbers
      }


      if (nonZeroIndex % 4 == 0 &&
          subText.length == nonZeroIndex &&
          nonZeroIndex > 4) {
        int moveCursorToRigth = nonZeroIndex ~/ 4 - 1;
        realTrimOffset += moveCursorToRigth;
      }

      if (nonZeroIndex % 4 != 0 && subText.length == nonZeroIndex) {
        int moveCursorToRigth = nonZeroIndex ~/ 4;
        realTrimOffset += moveCursorToRigth;
      }
    }

    var string = buffer.toString();
    return newValue.copyWith(
        text: string,
        selection: new TextSelection.collapsed(offset: realTrimOffset));
  }

in flutter 2.2 you should use FilteringTextInputFormatter.allow(RegExp(r'[0-9]')) instead of FilteringTextInputFormatter.digitsOnly

Related