I'm trying to a create custom InputTextFormatter. The formatter separates thousands with spaces and limits amount of characters after a dot to 2 chars.

I want to move the cursor to the end of the TextField value, but it looks like the real cursor moves further according to how many times I've tried to enter additional characters after reaching the limit (2 chars). It looks like selection not applies to resulting TextEditingValue.

Steps to reproduce:

  1. Enter a '12.34' to TextField.
  2. Keeping previous value try to add '111' for example.
  3. Press backspace. Nothing happens.

Expected behavior: pressing backspace once must delete the last character in the TextField.

class MoneyFormatter extends TextInputFormatter {
  MoneyFormatter({this.maxLength = 30, this.decimals = 0});
  final int maxLength;
  final int decimals;

  TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
    print('---------- newValue.selection.extentOffset : ${newValue.selection.extentOffset}');
    String output = newValue.text.formatAsCurrency(decimals: decimals);
    var result = TextEditingValue(
      text: output,
      //this line doesn't have any effect
      selection: TextSelection.collapsed(offset: output.length),
    print('---------- result.selection.extentOffset : ${result.selection.extentOffset}');
    return result;

With every additional character result.selection.extentOffset stays the same but newValue.selection.extentOffset increases by 1 despite the fact returning selection: TextSelection.collapsed(offset: output.length)

extension FormatAsCurrency on String {
  String formatAsCurrency({int decimals = 0, String ifNullReturn}) {
    if (this == null) return ifNullReturn;
    if (this.isEmpty) return '';
    String output = this;
    if (output[0] == '.') output = '0' + output;
    var chunks = this.withoutTrailingDots.split('.');
    output = chunks[0].separatedThousands;
    if (decimals == 0 || chunks.length == 1) return output;
    output += '.' + chunks[1].limitLengthTo(decimals).withoutTrailingZeros;
    return output;

I'm aware there are other TextInputFormatters on pub.dev like flutter_multi_formatter, I've tried all of them, the problem stays the same.

Solution 1: user8339163

Use \b in your regex :

                            controller: tvMobile,
                            keyboardType: TextInputType.number,
                            inputFormatters: <TextInputFormatter>[
                                  RegExp(r'[0-9,\b]')), // <-- Use \b in your regex here so backspace works.
                            maxLength: 10,
                            style: TextStyle(
                              color: Colors.white,
                              fontFamily: "Roboto",
                              fontWeight: FontWeight.w300,
                            decoration: InputDecoration(
                              labelStyle: TextStyle(
                                color: Colors.white,
                                fontFamily: "Roboto",
                                fontWeight: FontWeight.w300,
                              fillColor: Colors.white,
                              enabledBorder: UnderlineInputBorder(
                                    BorderSide(color: Colors.yellow),
                              focusedBorder: UnderlineInputBorder(
                                    BorderSide(color: Colors.yellow),
                              hintText: 'Mobile Number',
                              hintStyle: TextStyle(
                                color: Colors.grey,
                                fontFamily: "Roboto",
                                fontWeight: FontWeight.w300,

Solution 2: Kata Sanguansat

I found the backspacing problem when I try to use formatter with keyboard types number. The cursor tends to skip character(s) for each backspacing. It works fine if I use keyboard type text.