Flutter: TextFiled become clear when add new number - flutter

In my application i have a text field.I create a TextInputFormatter to add as a inputFormatters to my TextField:
class CurrencyTextInputFormatter extends TextInputFormatter {
#override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue, TextEditingValue newValue) {
if (newValue.text.isEmpty) {
return newValue.copyWith(text: '');
} else if (newValue.text.compareTo(oldValue.text) != 0) {
var selectionIndexFromTheRight =
newValue.text.length - newValue.selection.end;
final f =
NumberFormat.currency(locale: 'en', decimalDigits: 0, symbol: '');
var num = int.parse(newValue.text.replaceAll(RegExp('[^0-9]'), ''));
final newString = f.format(num).trim();
return TextEditingValue(
text: newString,
selection: TextSelection.collapsed(
offset: newString.length - selectionIndexFromTheRight),
);
} else {
return newValue;
}
}
}
everything is ok and when i add a price in TextField, the price is separated with , from right to left.
TextField(
textAlignVertical: TextAlignVertical.center,
controller: amountController,
inputFormatters: [
CurrencyTextInputFormatter(),
LengthLimitingTextInputFormatter(15),
],
In the parent of TextField in initState i initialized text field controller :
#override
void initState() {
super.initState();
amountController.text =
commaFormatter.format(widget.provider.totalUnpaidAmount);
}
commaFormatter use NumberFormat from intl to add comma between numbers:
final commaFormatter = NumberFormat("#,###");
The problem is here:
When number added to textfield by it's controller, when i want to delete this number by softkeyboard delete key, the number is not deleted ?But when i add a a new number, the old number completely deleted !!!!
How can i fix this problem?
I want to when number is added to this textfiled, Be editable !!!

Related

How to restrict the user from entering space at the beginning in a textfield in flutter?

inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'^[^\s][a-zA-Z ]')),
],
I tried this regex expression in the TextFormField but it is not taking alphabets also. I want the text field to restrict the space at the beginning but allow in the middle.
How to achieve it?
You should use TextEditingController:
final TextEditingController controller = TextEditingController();
TextFormField(
controller: controller,
),
controller.text.trimLeft()
just use function
trimLeft()
with your TextEditingController Like this
yourController.text.trimLeft()
class CustomFormatter extends TextInputFormatter {
CustomFormatter();
#override
TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
if (newValue.text.isNotEmpty) {
if (newValue.text.length > oldValue.text.length) {
return TextEditingValue(text: newValue.text.trimLeft(), selection: TextSelection.collapsed(offset: newValue.text.trim().isNotEmpty ? newValue.selection.end : 0));
} else {
return newValue;
}
}
return newValue;
}
}
TextField(
inputFormatters: [CustomFormatter()],
),
I would use the controller like MyCar said and additionaly put a logic in the onChanged() method of the text field. Then just check if the first character is space and if yes, remove it.
TextFormField(
controller: controller,
onChanged: (value) {
if (value.isNotEmpty) {
if (value[0] == " ") {
controller.text = value.trimLeft();
}
}
},
),
Your regex only allows one symbol in range of [a-zA-Z]. To allow multiple symbols you should try this:
RegExp(r'^[^\s][a-zA-Z ]*$')
or shorter:
RegExp(r'^\S[a-zA-Z ]*$')

split text in textformfield with a character in flutter

perhaps someone has encountered such a problem, I need to configure textformfield so that the text is entered in the form in the format / so that the user does not have to type / himself, it seems like you need to use inputformatter, but I can't figure out how to do it
maskformatter.dart
class MaskedTextInputFormatter extends TextInputFormatter {
final String? mask;
final String? separator;
MaskedTextInputFormatter({
#required this.mask,
#required this.separator,
}) {
assert(mask != null);
assert(separator != null);
}
#override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue, TextEditingValue newValue) {
if (newValue.text.isNotEmpty) {
if (newValue.text.length > oldValue.text.length) {
if (newValue.text.length > mask!.length) return oldValue;
if (newValue.text.length < mask!.length &&
mask![newValue.text.length - 1] == separator) {
return TextEditingValue(
text:
'${oldValue.text}$separator${newValue.text.substring(newValue.text.length - 1)}',
selection: TextSelection.collapsed(
offset: newValue.selection.end + 1,
),
);
}
}
}
return newValue;
}
in textfield use :-
inputFormatter: [
MaskedTextInputFormatter(
mask: '****-****-****-****',
separator: '-',
),
]
I think you are looking for mask text. Try this package mask_text
var maskFormatter = new MaskTextInputFormatter(
mask: '+# (###) ###-##-##',
filter: { "#": RegExp(r'[0-9]') },
type: MaskAutoCompletionType.lazy
);
And assign it to the textfield
TextField(inputFormatters: [maskFormatter])

Flutter Text Field allow user to insertion of a number within a given range only

I would to force the insertion of only values between 1-20. if user enter 2 it's okay but if user enter 1 after 2 (21) then Text Field will not allow to enter 1 after 2. Is there any RegExp for it.
I tried like this but it's only allow for numbers
inputFormatters: [FilteringTextInputFormatter.allow(RegExp('[1-9,.,:]'))],
Try below code hope its help to you. in below code if you put more than 20 value the cursor takes the first position.
Create one class and declare it minimum and maximum value.
class LimitRange extends TextInputFormatter {
LimitRange(
this.minRange,
this.maxRange,
) : assert(
minRange < maxRange,
);
final int minRange;
final int maxRange;
#override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue, TextEditingValue newValue) {
var value = int.parse(newValue.text);
if (value < minRange) {
print('value print in between 1 - 20');
return TextEditingValue(text: minRange.toString());
} else if (value > maxRange) {
print('not more 20');
return TextEditingValue(text: maxRange.toString());
}
return newValue;
}
}
Your Widget:
TextField(
keyboardType: TextInputType.number,
inputFormatters: [
LengthLimitingTextInputFormatter(2),
LimitRange(1, 20),
],
),

How to change color of particular text in a text field dynamically?

Consider bellow image, I want to dynamically change the text color of part of the text based on the user input text (not the whole text) in a text field. How can i do that in flutter?
For this example we actually don't need a full blown rich-text editor.
I had a similar goal in my app to highlight tags (#flutter) or date references (next week, on Friday, etc) and I was able to implement this by extending built-in EditableText widget and posted my example as a Gist here: https://gist.github.com/pulyaevskiy/d7af7217c2e71f31dfb78699f91dfbb5
Below is full implementation of this widget which I called AnnotatedEditableText.
There is new property annotations which describes ranges of text that need to be highlighted and their style.
import 'package:flutter/widgets.dart';
class Annotation extends Comparable<Annotation> {
Annotation({#required this.range, this.style});
final TextRange range;
final TextStyle style;
#override
int compareTo(Annotation other) {
return range.start.compareTo(other.range.start);
}
#override
String toString() {
return 'Annotation(range:$range, style:$style)';
}
}
class AnnotatedEditableText extends EditableText {
AnnotatedEditableText({
Key key,
FocusNode focusNode,
TextEditingController controller,
TextStyle style,
ValueChanged<String> onChanged,
ValueChanged<String> onSubmitted,
Color cursorColor,
Color selectionColor,
TextSelectionControls selectionControls,
this.annotations,
}) : super(
key: key,
focusNode: focusNode,
controller: controller,
cursorColor: cursorColor,
style: style,
keyboardType: TextInputType.text,
autocorrect: true,
autofocus: true,
selectionColor: selectionColor,
selectionControls: selectionControls,
onChanged: onChanged,
onSubmitted: onSubmitted,
);
final List<Annotation> annotations;
#override
AnnotatedEditableTextState createState() => new AnnotatedEditableTextState();
}
class AnnotatedEditableTextState extends EditableTextState {
#override
AnnotatedEditableText get widget => super.widget;
List<Annotation> getRanges() {
var source = widget.annotations;
source.sort();
var result = new List<Annotation>();
Annotation prev;
for (var item in source) {
if (prev == null) {
// First item, check if we need one before it.
if (item.range.start > 0) {
result.add(new Annotation(
range: TextRange(start: 0, end: item.range.start),
));
}
result.add(item);
prev = item;
continue;
} else {
// Consequent item, check if there is a gap between.
if (prev.range.end > item.range.start) {
// Invalid ranges
throw new StateError(
'Invalid (intersecting) ranges for annotated field');
} else if (prev.range.end < item.range.start) {
result.add(Annotation(
range: TextRange(start: prev.range.end, end: item.range.start),
));
}
// Also add current annotation
result.add(item);
prev = item;
}
}
// Also check for trailing range
final String text = textEditingValue.text;
if (result.last.range.end < text.length) {
result.add(Annotation(
range: TextRange(start: result.last.range.end, end: text.length),
));
}
return result;
}
#override
TextSpan buildTextSpan() {
final String text = textEditingValue.text;
if (widget.annotations != null) {
var items = getRanges();
var children = <TextSpan>[];
for (var item in items) {
children.add(
TextSpan(style: item.style, text: item.range.textInside(text)),
);
}
return new TextSpan(style: widget.style, children: children);
}
return new TextSpan(style: widget.style, text: text);
}
}
Rich text controller works fine!
See more on https://pub.dev/packages/rich_text_controller
First you choose your RegExp
RichTextController _controller;
Map<RegExp, TextStyle> patternUser = {
RegExp(r"\B#[a-zA-Z0-9]+\b"):
TextStyle(color: Colors.amber, fontWeight: FontWeight.bold)
};
on initState()
_controller = RichTextController(
patternMap: patternUser,
);
Add controller on your TextFormField
TextFormField(
controller: _controller,
style: TextStyle(color: Colors.white),
)

Is there a way for InputFormatters on a TextFormField to be executed when the form is initially displayed?

When inputFormatters are specified on a TextFormField, the initialValue is not processed by the inputFormatters.
This seems odd. Is there a recommended way to get the inputFormatters to format the initialValue.
For example, I have a 5 digit number (i.e. 12345) that should be displayed with a comma separator (12,345) in the input field. By default it displays as 12345, but as soon as I edit the value, the comma separator appears. The comma separator should be displayed on the initial value.
You can create a static method to validate your initialValue
class MyFormater extends TextInputFormatter {
static String defaultFormat(String text) {
// Do whatever you want
return text;
}
#override
TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
// Your validations/formats
return null;
}
}
and then you can use it as so
TextFormField(
initialValue: MyFormater.defaultFormat(someString),
inputFormatters: [MyFormater()],
)
I doubt there is other way that will trigger the TextInputFormatter before it has any focus. That initialValue is mean to be already validated and work as a placeholder.
you can use this to set the text directly to the controller without interacting with the text field
var textEditingController = TextEditingController();
textEditingController.value = myFormatter.formatEditUpdate(TextEditingValue(text: ''), TextEditingValue(text: 'my initial value'));
you can set custom inputFormatters in TextField.
for that you must define your filter, for example a function that take String and return a neat( or filtered ) String.
in my case function neatCost() get a string and separate 3 by 3 chars by "," for example take "12345" and return "12,345".
for creating custom inputFormatters :
class NeatCostFilterFormatter extends TextInputFormatter {
#override
TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
final StringBuffer newText = StringBuffer();
newText.write(neatCost(newValue.text.replaceAll(",", "")));
print(newValue.text);
print(neatCost(newValue.text.replaceAll(",", "")).length);
return TextEditingValue(
text: newText.toString(),
selection: TextSelection.collapsed(offset: neatCost(newValue.text.replaceAll(",", "")).length),
);
}
}
and the function:
String neatCost(String cost) {
String res=cost;
if(cost!=null) {
for (int i = 3; i < res.length; i += 4) {
res = res.replaceRange(res.length - i, res.length - i, ",");
}
return res;
}else{
return "";
}
}
after that yo can set your custom formatter to the TextField just like this:
new TextField(
inputFormatters: <TextInputFormatter>[new NeatCostFilterFormatter()]
)