skip to Main Content

I want have a TextFormField that formats the input depending on a given separator and interval.

E.g. separator = '-' and interval = 4 the output should be the following:

Input: 1234 Output: 1234

Input 12345678 Output: 1234-5678

Input: 12345678910 Output: 1234-5678-910

The separator should be inserted right when the user types in the 5th character in this example.

I tried multiple things now, but can not get a general working solution. That was my last try:

  void _addSeperator(String value) {
    final separator = widget.separator!;
    final separatorInterval = widget.separatorInterval!;

    value = value.replaceAll(separator, ''); // Remove existing separators
    int length = value.length;
    int separatorCount = (length / separatorInterval).floor();
    for (int i = 1; i <= separatorCount; i++) {
      int index = i * separatorInterval +
          (i - 1); // Calculate the index to insert separator
      if (index < length) {
        value = value.substring(0, index) +
            separator +
            value.substring(index, value.length);
      }
    }

    _controller.text = value;
  }

I thought this shouldnt be that hard, but I can not make it work. Also didn’t find anything on this. Let me know if you need more info.

2

Answers


  1. It looks like you are trying to format credit card numbers. Flutter already comes with 2 handful formatter that you could use, FilteringTextInputFormatter and LengthLimitingTextInputFormatter. You could also extends TextInputFormatter and implement your custom formatting logic.

    Below is a simple example.

    FilteringTextInputFormatter.allow(RegExp(r'd')) only allows digits.
    LengthLimitingTextInputFormatter(16) set the max input length to 16.
    CreditCardNumberFormatter is a custom formatter that adds a separator between every 4 digits.

    TextFormField(
      inputFormatters: [
        FilteringTextInputFormatter.allow(RegExp(r'd')),
        LengthLimitingTextInputFormatter(16),
        const CreditCardNumberFormatter(),
      ],
      ...
    ),
    
    class CreditCardNumberFormatter extends TextInputFormatter {
      const CreditCardNumberFormatter({
        this.separator = '-',
        this.interval = 4,
      });
    
      final String separator;
      final int interval;
    
      @override
      TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
        final text = newValue.text;
        final buffer = StringBuffer();
        for (var i = 0; i < text.length; i++) {
          if (i % interval == 0 && i != 0) {
            buffer.write(separator);
          }
          buffer.write(text[i]);
        }
    
        return TextEditingValue(
          text: buffer.toString(),
          selection: TextSelection.collapsed(offset: buffer.length),
        );
      }
    }
    
    Login or Signup to reply.
  2. You can use the very popular library mask_text_input_formatter to format the text within a specific format. See its documentation on how to use it.

    var textEditingController = TextEditingController(text: "12345678");
    var maskFormatter = new MaskTextInputFormatter(mask: '####-####', filter: { "#": RegExp(r'[0-9]') });
    
    TextField(controller: textEditingController, inputFormatters: [maskFormatter])  // -> "1234-5678"
    
    textEditingController.value = maskFormatter.updateMask(mask: "##-##-##-##"); // -> "12-34-56-78"
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search