formatEditUpdate method
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(
final TextEditingValue oldValue,
final TextEditingValue newValue,
) {
// print('old: ${oldValue.toJSON()}');
// print('new: ${newValue.toJSON()}');
int signals = RegExp('-').allMatches(newValue.text).length;
bool isNegative = oldValue.text.startsWith('-');
bool delNegative = false;
if (isNegative && signals != 1) {
isNegative = false;
delNegative = true;
}
if (!isNegative && signals == 1) {
isNegative = true;
}
String newText = newValue.text.replaceAll('-', '');
/// Empty value
if (newText.isEmpty ||
newText == decimalSeparator ||
newText == thousandSeparator) {
// print('New value is empty or equals to "$decimalSeparator" '
// 'or equals to "$thousandSeparator"');
// print('\n');
return TextEditingValue(
text: '${isNegative ? '-0' : '0'}$decimalSeparator'.padRight(
precision + (isNegative ? 3 : 2),
'0',
),
selection: TextSelection.collapsed(offset: (isNegative ? 2 : 1)),
);
}
/// Char not allowed.
if (allow.allMatches(newText).length != newText.length) {
// print('Char not allowed.');
// print('\n');
return oldValue;
}
int oldDecimalCount = oldValue.text.split(decimalSeparator).length;
int oldThousandCount = oldValue.text.split(thousandSeparator).length;
int newDecimalCount = newText.split(decimalSeparator).length;
int newThousandCount = newText.split(thousandSeparator).length;
if (oldDecimalCount < newDecimalCount ||
oldThousandCount < newThousandCount) {
int curPos = oldValue.text.indexOf(decimalSeparator) + 1;
// print('curPos: $curPos');
if (newValue.selection.baseOffset <= curPos) {
Map<String, dynamic> oldValueJson = oldValue.toJSON();
oldValueJson['selectionBase'] = curPos;
oldValueJson['selectionExtent'] = curPos;
// print('\n');
return TextEditingValue.fromJSON(oldValueJson);
}
// print('\n');
return oldValue;
}
/// Decimal Part
if (newText.contains(decimalSeparator)) {
List<String> parts = newText.split(decimalSeparator);
// print('Integer Part: ${parts.first}');
// print('Decimal Part: ${parts.last}');
String decimalPart = parts.last;
decimalPart = decimalPart.length > precision
? decimalPart.substring(0, precision)
: decimalPart.padRight(precision, '0');
newText = '${parts.first}$decimalSeparator$decimalPart';
} else {
if (newText.length == 1) {
newText += decimalSeparator.padRight(precision + 1, '0');
} else {
int pos = newText.length - precision;
newText =
newText.substring(0, pos) +
decimalSeparator +
newText.substring(pos);
}
}
int firstLength = newText.length;
/// Integer Part
List<String> parts = newText.split(decimalSeparator);
int integerPart =
int.tryParse(parts.first.replaceAll(thousandSeparator, '')) ?? 0;
List<String> numbers = integerPart.toString().split('').reversed.toList();
for (int pos = 3; pos < numbers.length; pos += 4) {
numbers.insert(pos, thousandSeparator);
}
newText = numbers.reversed.join() + decimalSeparator + parts.last;
/// Cursor Positioning
int newTextLength = newText.length;
int newPos = newValue.selection.baseOffset;
// print('newPos: $newPos');
newPos += newTextLength - firstLength;
// print('delta: ${newTextLength - firstLength}');
if (delNegative) {
newPos -= 2;
}
if (newPos < 1) {
newPos = 0;
}
newText = (isNegative ? '-' : '') + newText;
if (newPos > newText.length) {
newPos = newText.length;
}
Map<String, dynamic> newValueJson = newValue.toJSON();
newValueJson['text'] = newText;
newValueJson['selectionBase'] = newPos;
newValueJson['selectionExtent'] = newPos;
// print('newValueJson: $newValueJson');
// print('\n');
return TextEditingValue.fromJSON(newValueJson);
}