Search code examples
stringflutterdartformatter

Flutter add separator character after given interval in TextFormField


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.


Solution

  • I got it working with this:

    class UISeparatorInputFormatOptions {
      final String separator;
      final int interval;
    
      UISeparatorInputFormatOptions({
        required this.separator,
        required this.interval,
      });
    }
    
    class UISeparatorInputFormatter extends TextInputFormatter {
      /// IMPORTANT: String must not contain the options.separator
      /// otherwise this InputFormatter will not work correctly.
      final UISeparatorInputFormatOptions options;
    
      UISeparatorInputFormatter({
        required this.options,
      });
    
      @override
      TextEditingValue formatEditUpdate(
        TextEditingValue oldValue,
        TextEditingValue newValue,
      ) {
        // Remove existing separators
        String newText = newValue.text.replaceAll(
          options.separator,
          '',
        );
    
        StringBuffer buffer = StringBuffer();
        for (int i = 0; i < newText.length; i++) {
          if (i > 0 && i % options.interval == 0) {
            buffer.write(options.separator);
          }
          buffer.write(newText[i]);
        }
    
        String formattedString = buffer.toString();
        return newValue.copyWith(
          text: formattedString,
          // This ensures that the cursor follows the text properly
          selection: TextSelection.collapsed(offset: formattedString.length),
        );
      }
    }