siqwin / mask_text_input_formatter

Masked text input formatter for flutter.
MIT License
254 stars 54 forks source link

mask_text_input_formatter where symbols are replaced #95

Open 8a5n7d3y opened 4 months ago

8a5n7d3y commented 4 months ago

Hi there,

I am wondering if there is a way to extend somehow MaskTextInputFormatter class where instead of insertion of symbols while typing they will be replaced, and there is no way to remove them, only replace, hence fixed text length. For example: initial value is 01-20>05 , and say cursor is at the position 0, and I type 5, the result will be 51-20>05, not 50-12>00.

I tried to extend the MaskTextInputFormatter, got it working with some simple masks, but with more complex ones it becomes complicated. And it seems to me that, there is a simpler solution. Also tried to chain input formatters, got something working but not reliable.

Would be greatfull for any ideas, or solutions.

Thanks, Andy

8a5n7d3y commented 4 months ago

Below class would work more or less fine when the mask doesn't have any separators, say mask '####', but with a mask say as '##-##-###', this would require parsing of the mask in the class as well. There is got to be an easier solution.

class SymbolReplacerFormatter extends MaskTextInputFormatter {
   SymbolReplacerFormatter({
        super.mask,
        super.filter,
        super.initialText,
        super.type,
    });

  @override
  TextEditingValue formatEditUpdate(
      TextEditingValue oldValue, TextEditingValue newValue) {
    final cursorPosition = oldValue.selection.baseOffset;
    String? lastTypedSymbol;
    String? updatedText;
    int? updatedOffset;

    if ((oldValue.text.isEmpty &&
          newValue.text.isNotEmpty &&
          getMask() != null &&
          newValue.text.length == getMask()!.length) || (cursorPosition == -1)) {
      return super.formatEditUpdate(oldValue, newValue);
    }

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

    var tbr = super.formatEditUpdate(oldValue, newValue);
    lastTypedSymbol = newValue.text.substring(cursorPosition, cursorPosition + 1);

    if (cursorPosition >= oldValue.text.length) {
      updatedText = oldValue.text;
      updatedOffset = getMask()!.length;
    } else {
      updatedText = oldValue.text.replaceRange(cursorPosition, cursorPosition + 1, lastTypedSymbol);
      updatedOffset = newValue.selection.baseOffset;
    }

    super.formatEditUpdate(const TextEditingValue(text: ""),
        TextEditingValue(
            text: updatedText,
            selection: TextSelection.collapsed(offset: updatedOffset),
        )
    );

    return TextEditingValue(
        text: updatedText,
        selection: TextSelection.collapsed(offset: updatedOffset),
    );
  }
}