Reputation: 2044
I'm trying to find a way to add a blank space while typing in a TextFormField
.
I found a way how to do this a while back but I cannot find it now, no matter what I search for on Google or here on StackOverflow ..
Basically I want to turn the text shown in the textfield from 000011112222333
to 0000 1111 2222 3333
I'm guessing I need to use some RegExp
check in the onChanged
function of a TextFormField
and use it to change the TextEditingController
's .text
Upvotes: 7
Views: 10606
Reputation: 101
I have used this for inserting space after every 2 characters, you can change it for 4 characters:
class SpaceFormatter extends TextInputFormatter {
@override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue,
TextEditingValue newValue,
) {
String text = newValue.text.replaceAll(' ', '');
String newText = '';
for (int i = 0; i < text.length; i++) {
if (i > 0 && i % 2 == 0) {
newText += ' ';
}
newText += text[i];
}
return TextEditingValue(
text: newText,
selection: TextSelection.collapsed(offset: newText.length),
);
}
}
And then you can use it like this:
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r"[0-9]")),
SpaceFormatter(),
],
Upvotes: 1
Reputation: 51
TextFormField(
inputFormatters: [
LengthLimitingTextInputFormatter(12),
TextInputFormatter.withFunction((oldValue, newValue) {
String left = oldValue.text.substring(
0, min(oldValue.selection.start, newValue.selection.end));
String right =
oldValue.text.substring(oldValue.selection.end);
String inserted = newValue.text
.substring(left.length, newValue.selection.end);
String modLeft = left.replaceAll(RegExp(r'\D'), "");
String modRight = right.replaceAll(RegExp(r'\D'), "");
String modInserted = inserted.replaceAll(RegExp(r'\D'), "");
final regEx = RegExp(r'\d{1,4}');
String processString = modLeft + modInserted + modRight;
String updated = regEx
.allMatches(processString)
.map((e) => e.group(0))
.join(" ");
int cursorPosition = regEx
.allMatches(modLeft + modInserted)
.map((e) => e.group(0))
.join(" ")
.length;
return TextEditingValue(
text: updated,
selection:
TextSelection.collapsed(offset: cursorPosition));
})
],
)
Upvotes: 0
Reputation: 11210
This is very easy to do using a parser as a data processor.
import 'package:parser_combinator/parser/choice.dart';
import 'package:parser_combinator/parser/many.dart';
import 'package:parser_combinator/parser/take_while1.dart';
import 'package:parser_combinator/parser/take_while_m_n.dart';
import 'package:parser_combinator/parsing.dart';
void main(List<String> args) {
for (var i = 0; i < 24; i++) {
final text = String.fromCharCodes(List.generate(i, (i) => 0x61 + i));
final newText = convert(text);
print('$text => $newText');
}
const test = ' a bcd ef ghi ';
final r = convert(test);
print('$test => $r');
}
String convert(String text) {
text = text.replaceAll(' ', '');
const word4 = TakeWhileMN(4, 4, isAnyChar);
const rest = TakeWhile1(isAnyChar);
const words = Many(Choice2(word4, rest));
final r = parseString(words.parse, text);
return r.join(' ');
}
bool isAnyChar(int c) => true;
Output:
=>
a => a
ab => ab
abc => abc
abcd => abcd
abcde => abcd e
abcdef => abcd ef
abcdefg => abcd efg
abcdefgh => abcd efgh
abcdefghi => abcd efgh i
abcdefghij => abcd efgh ij
abcdefghijk => abcd efgh ijk
abcdefghijkl => abcd efgh ijkl
abcdefghijklm => abcd efgh ijkl m
abcdefghijklmn => abcd efgh ijkl mn
abcdefghijklmno => abcd efgh ijkl mno
abcdefghijklmnop => abcd efgh ijkl mnop
abcdefghijklmnopq => abcd efgh ijkl mnop q
abcdefghijklmnopqr => abcd efgh ijkl mnop qr
abcdefghijklmnopqrs => abcd efgh ijkl mnop qrs
abcdefghijklmnopqrst => abcd efgh ijkl mnop qrst
abcdefghijklmnopqrstu => abcd efgh ijkl mnop qrst u
abcdefghijklmnopqrstuv => abcd efgh ijkl mnop qrst uv
abcdefghijklmnopqrstuvw => abcd efgh ijkl mnop qrst uvw
a bcd ef ghi => abcd efgh i
Upvotes: 0
Reputation: 156
in flutter 2.2 you should use FilteringTextInputFormatter.allow(RegExp(r'[0-9]'))
instead of FilteringTextInputFormatter.digitsOnly
Upvotes: -2
Reputation: 126
Inspired from Dung Ngo's Code
I added cursor tracking so when the user erases from the the TextFormField the cursor doesn't goes back to the beginning of field.
I commented the WhitelistingTextInputFormatter.digitsOnly / FilteringTextInputFormatter.digitsOnly in my pen since I used regular expressions.
Here's the pen https://codepen.io/brocatz/pen/dyNOqVy
@override
TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
var text = newValue.text;
text = text.replaceAll(RegExp(r'(\s)|(\D)'), '');
int offset = newValue.selection.start;
var subText =
newValue.text.substring(0, offset).replaceAll(RegExp(r'(\s)|(\D)'), '');
int realTrimOffset = subText.length;
// if (newValue.selection.baseOffset == 0) {
// return newValue;
// }
var buffer = new StringBuffer();
for (int i = 0; i < text.length; i++) {
buffer.write(text[i]);
var nonZeroIndex = i + 1;
if (nonZeroIndex % 4 == 0 && nonZeroIndex != text.length) {
buffer.write(
' '); // Replace this with anything you want to put after each 4 numbers
}
if (nonZeroIndex % 4 == 0 &&
subText.length == nonZeroIndex &&
nonZeroIndex > 4) {
int moveCursorToRigth = nonZeroIndex ~/ 4 - 1;
realTrimOffset += moveCursorToRigth;
}
if (nonZeroIndex % 4 != 0 && subText.length == nonZeroIndex) {
int moveCursorToRigth = nonZeroIndex ~/ 4;
realTrimOffset += moveCursorToRigth;
}
}
var string = buffer.toString();
return newValue.copyWith(
text: string,
selection: new TextSelection.collapsed(offset: realTrimOffset));
}
Upvotes: 5
Reputation: 1472
I also faced this problem before and luckily found a way to do this somewhere. First create a class that extends TextInputFormatter
customInputFormatter.dart
class CustomInputFormatter extends TextInputFormatter {
@override
TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
var text = newValue.text;
if (newValue.selection.baseOffset == 0) {
return newValue;
}
var buffer = new StringBuffer();
for (int i = 0; i < text.length; i++) {
buffer.write(text[i]);
var nonZeroIndex = i + 1;
if (nonZeroIndex % 4 == 0 && nonZeroIndex != text.length) {
buffer.write(' '); // Replace this with anything you want to put after each 4 numbers
}
}
var string = buffer.toString();
return newValue.copyWith(
text: string,
selection: new TextSelection.collapsed(offset: string.length)
);
}
}
And then add it to the list of inputFormatters[] of TextFormField
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
new CustomInputFormatter()
],
Upvotes: 20