formatEditUpdate method

  1. @override
TextEditingValue formatEditUpdate(
  1. TextEditingValue oldValue,
  2. TextEditingValue newValue
)
override

Called when text is being typed or cut/copy/pasted in the EditableText.

You can override the resulting text based on the previous text value and the incoming new text value.

When formatters are chained, oldValue reflects the initial value of TextEditingValue at the beginning of the chain.

Implementation

@override
TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
  locale ??= platformLocaleCode;
  var form = NumberFormat.decimalPattern(locale);
  decimalDigits ??= form.decimalDigits ?? 4;
  var simb = form.symbols;
  var decimalSeparator = simb.DECIMAL_SEP;
  var minusSign = simb.MINUS_SIGN;
  var percentSign = simb.PERCENT;

  String formattedValue = "";

  string newValueText = newValue.text.trimAll;

  // Remove any non-digit characters
  for (int i = 0; i < newValueText.length; i++) {
    var e = newValueText.charAt(i);
    if (i == 0 && (e == minusSign)) {
      formattedValue += e;
      continue;
    }
    if (e.isNumber) {
      formattedValue += e;
      continue;
    }
    if (e == decimalSeparator && !formattedValue.contains(decimalSeparator)) {
      formattedValue += e;
      continue;
    }
    if (e == percentSign && i == newValueText.length - 1) {
      formattedValue += e;
      continue;
    }
  }

  // Check if the first character is a plus or minus sign
  bool isNegative = false;
  if (formattedValue.isNotEmpty && (formattedValue[0] == minusSign)) {
    isNegative = formattedValue[0] == minusSign;
    formattedValue = formattedValue.substring(1);
  }

  // Check if the last character is a percent sign
  bool hasPercentSign = false;
  if (formattedValue.isNotEmpty && formattedValue[formattedValue.length - 1] == percentSign) {
    hasPercentSign = true;
    formattedValue = formattedValue.substring(0, formattedValue.length - 1);
  }

  // Check if the newText contains a decimal separator
  bool hasDecimalSeparator = formattedValue.contains(decimalSeparator);

  // Split the newText into integer and decimal parts
  List<String> parts = formattedValue.split(decimalSeparator);
  String integerPart = parts[0];
  String decimalPart = (parts.length > 1 ? parts[1] : '').first(decimalDigits!);

  // Format the integer part
  formattedValue = NumberFormat.decimalPattern(locale).format(int.parse(integerPart));

  // Add the decimal separator and decimal part if necessary
  if (hasDecimalSeparator) {
    formattedValue += '$decimalSeparator$decimalPart';
  }

  // Add the percent sign if necessary
  if (hasPercentSign) {
    if (calculateDecimal) {
      formattedValue = (double.parse(formattedValue.removeAny([percentSign])) / 100).toStringAsFixed(decimalDigits!);
    } else {
      formattedValue += percentSign;
    }
  }

  // Add the plus or minus sign if necessary
  if (isNegative) {
    formattedValue = '$minusSign$formattedValue';
  }

  return TextEditingValue(
    text: formattedValue,
    selection: TextSelection.collapsed(offset: (formattedValue.contains(percentSign) ? formattedValue.indexOf(percentSign) - 1 : formattedValue.length).clamp(0, formattedValue.length - 1)),
  );
}