when I do backspacing on a text, and then type again, the typing does not show up in the text field and the backspacing itself doesn't work good. I don't know if the problem is with the flutter itself or what because many people have the same issue.
TextField(
controller: controller,
maxLength: 9,
keyboardType: TextInputType.text,
textCapitalization: TextCapitalization.characters,
onChanged: (text) {
if (7 > pin.length) {
final String newText = _addDashes(text);
controller.text = newText;
controller.selection =
TextSelection.collapsed(offset: newText.length);
}
pin = text;
},
textAlign: TextAlign.left,
// keyboardType: TextInputType.visiblePassword,
decoration: InputDecoration(
errorText: _errorText,
icon: Icon(
Icons.dialpad,
),
labelText: '8-digit PIN',
contentPadding: EdgeInsets.symmetric(vertical: 10.0),
focusedBorder: UnderlineInputBorder(
borderSide:
BorderSide(color: Colors.transparent, width: 2),
),
focusedErrorBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.red, width: 2),
),
errorBorder: UnderlineInputBorder(
borderSide:
BorderSide(color: Color(0xFFF696969), width: 1),
),
),
),
You can change your callback position from OnChnage to custom listener on controller. E.g.
controller.addListener(() {
if (7 > pin.length) {
final String newText = _addDashes(controller.text);
controller.value = _controller.value.copyWith(enter code here
text: newText,
selection: TextSelection.collapsed(offset: newText.length));
}
});
OR You can use same onChange Callback but use custom delayed as follows.
onChanged: (text) {
if (7 > pin.length) {
final String newText = _addDashes(text);
Future.delayed(Duration.zero, () {
controller.text = newText;
controller.selection = TextSelection.collapsed(offset:newText.length);
});
}
pin = text;
}
USING FUTURE DELAYD IN ONCHANGE WORKING FOR ME
this happened to me before and as per research, I found out that using controller and onChanged properties at the same time in a textField is what caused this error. I just can't find the doc where I read it but if I remember correctly, if you use controller, don't use onChanged or 'initialValue' and if some reason you need to use the onChanged or initialValue property, then the controller should be null.
According to the Flutter TextEditingController documentation, you should use a TextInputFormatter instead of editing the value of the TextEditingController using a listener; the issue is similar to that caused by the onChanged callback:
Gboard, for example, will try to restore the composing region of the text if it was modified programmatically, creating an infinite loop of communications between the framework and the input method.
A TextInputFormatter is one way to solve the issue. Others are moving the callback to onSubmitted or to a method that checks whether or not the widget has focus first.
Mask Text Input Formatter
Create Formatter
var maskFormatter = MaskTextInputFormatter(mask: '####-####', filter:
{"#": RegExp(r'[0-9]')}, type: MaskAutoCompletionType.eager);
And add your TextField formatters
TextField(
controller: controller,
maxLength: 9,
keyboardType: TextInputType.text,
textCapitalization: TextCapitalization.characters,
// here ->
inputFormatters: [maskFormatter],
textAlign: TextAlign.left,
// keyboardType: TextInputType.visiblePassword,
decoration: InputDecoration(
errorText: _errorText,
icon: Icon(
Icons.dialpad,
),
labelText: '8-digit PIN',
contentPadding: EdgeInsets.symmetric(vertical: 10.0),
focusedBorder: UnderlineInputBorder(
borderSide:
BorderSide(color: Colors.transparent, width: 2),
),
focusedErrorBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.red, width: 2),
),
errorBorder: UnderlineInputBorder(
borderSide:
BorderSide(color: Color(0xFFF696969), width: 1),
),
),
),
Finally get the data
maskFormatter.getMaskedText();
maskFormatter.getUnmaskedText();
Related
Hi, In flutter, How to create a text field that allows only numbers?
I'm unable to find a way to create an input field in Flutter that would open up a numeric keyboard and should take numeric input only. I tried. But I am getting errors.
Container(
width: 310,
TextEditingController _numberController = TextEditingController();
child: TextField(
controller: _numberController,
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly,
],
decoration: InputDecoration(
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xffbcbcbc)),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.cyan),
),
hintText: '+919876567876',
hintStyle: GoogleFonts.lato(
color: Color(0xff000000),
fontSize: 20,
letterSpacing: 0.5,
decorationThickness: 3)),
),
),
Add any of these line inside your TextField widget
keyboardType: TextInputType.number,
or
keyboardType: TextInputType.phone,
You should declare TextEditingController variable inside class, not inside Container Widget. For numeric input only, set ' keyboardType: TextInputType.number ' in TextField.
I have a TextField with its textDirection set to rtl (Right-to-Left). When I select the TextField, I expect the cursor go to the end, as usual, but cursor goes to one position before the end.
TextField(
textDirection: TextDirection.rtl,
controller: widget.controller,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(8),
isDense: true,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 2,
color: Theme.of(context).primaryColor,
),
borderRadius: BorderRadius.circular(8),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 1.7,
color: Colors.grey.withOpacity(0.3),
),
borderRadius: BorderRadius.circular(8),
),
),
),
);
How can I make the cursor appear at the end instead?
UPDATE: I realized that specifying controller in the TextField make the problem appear. but i need cotroller in this situation.
I think this because of each arabic character is encoded as 2 to 4 bytes.
Any way this code can do the trick
TextField(
onTap: (){
if(controller.selection == TextSelection.fromPosition(TextPosition(offset: controller.text.length -1))){
setState(() {
controller.selection = TextSelection.fromPosition(TextPosition(offset: controller.text.length));
});
}
},
controller: controller,
...
);
You can control cursor position by using TextSelection.
I didn't test Arabic environment, but try this.
offset value means position of cursor, so test 0 or (widget.controller.text.length)
TextField(
textDirection: TextDirection.rtl,
controller: widget.controller
..selection = TextSelection.fromPosition(TextPosition(offset: 0)),
decoration: InputDecoration(
contentPadding: EdgeInsets.all(8),
isDense: true,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 2,
color: Theme.of(context).primaryColor,
),
borderRadius: BorderRadius.circular(8),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 1.7,
color: Colors.grey.withOpacity(0.3),
),
borderRadius: BorderRadius.circular(8),
),
),
),
);
You can try this action to move the cursor to the end of the text. Then place this controller in the controller in TextField.:
late TextEditingController _textEditingController;
#override
void initState() {
_textEditingController = TextEditingController(text: widget.text);
_textEditingController.selection = TextSelection.fromPosition(
TextPosition(offset: _textEditingController.text.length));
super.initState();
}
You can fix it by add this function on your textfield
onTap: () {
if (searchController.text[searchController.text.length - 1] != ' ') {
searchController.text = (searchController.text + ' ');
}
if (searchController.selection ==TextSelection.fromPosition(
TextPosition(offset:
searchController.text.length - 1))) {
setState(() {});
}
}
When I tap on Text Field and write from keyboard then I click done,
all data from Text Field was cleared.
This is my code:
TextField(
controller: controller,
keyboardType: textInputType,
decoration: InputDecoration(
hintText: hintText,
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey, width: 0.5),
),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(
color: Colors.black,
width: 1,
),
),
),
)
my controller:
TextEditingController controller = TextEditingController();
I'm guessing this is a stateless widget, and you're instantiating the TextEditingController in it. Closing the keyboard is causing a rebuild and you're losing the state, and a new controller is being created. You'll want to use a stateful widget and put the TextEditingController in state.
I cant get the textfield labeltext to show. anyone can help? and how do I get the border to always showing and not disappear when I click on the text field.
#override
Widget build(BuildContext context) {
return TextFormField(
controller: _controller,
decoration: InputDecoration(
border: new OutlineInputBorder(
borderSide: new BorderSide(width: 1)
),
// hintText: _hintText,
labelText: "Label Text",
contentPadding: EdgeInsets.only(left: 15),
// suffixText: _nameLength.toString() + "/ " + _maxLength.toString(),
// suffixStyle: TextStyle(fontSize: 12),
// suffixStyle: TextStyle(color: Theme.of(context).textTheme.bodyText2.color),
// counterText: "",
),
maxLines: _maxLines,
textCapitalization: TextCapitalization.sentences,
cursorRadius: Radius.circular(10),
keyboardType: TextInputType.text,
autofocus: true,
maxLength: _showTextCount ? _maxLength : null,
style: TextStyle(color: AppSetting.textColor1),
validator: (val) {
// if (val.isEmpty) {
// return 'Please enter text.';
// }
// return null;
},
onChanged: (val) {
_onChanged(val);
setState(() {
_inputFieldText = val;
_nameLength = _inputFieldText.length;
});
},
onTap: () => AppSetting.hapticFeeback(),
);
}
}
You should add
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.redAccent,
width: 2.0,
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: primaryColor,
width: 2.0,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.black54,
width: 2.0,
),
),
),
Just make sure the default value of labelColor of the input decoration is different from background (the default label color was white in my case). In order to show border when clicked set focusedBorder property.
I have a custom text field but as shown in the picture, the bottom text fields looks so vague and empty, I'd like to keep the hint showing even if the field is not focused, how do I achieve that in flutter?
here is my widget code:
Container(
margin: EdgeInsets.all(20),
child: TextFormField(
autofocus: true,
textAlign: TextAlign.right,
decoration: InputDecoration(
enabledBorder: const OutlineInputBorder(
borderSide: const BorderSide(color: Color(0xff0E9447), width: 2.0),
),
focusedBorder: const OutlineInputBorder(
borderSide: const BorderSide(color: Color(0xff0E9447), width: 2.0),
),
hintText: AppStrings.email,
labelText: AppStrings.email,
alignLabelWithHint: true,
hintStyle: TextStyle(color: AppColors.primaryColorLight),
),
),
),
If you would like the label to be visible at the top of the TextField, and the hint displayed at the same time you can simply add:
floatingLabelBehavior: FloatingLabelBehavior.always
to the TextFields InputDecoration (decoration).
(At the time of writing this, there is a bug that will only show the hint and suffix upon focus, this has been fixed in a very recent PR and will be available shortly, see GitHub issue)
Full Example
TextFormField(
controller: textController,
style: theme.textTheme.bodyText2,
keyboardType: keyboardType ?? TextInputType.number,
enableInteractiveSelection: false,
decoration: InputDecoration(
labelText: labelText,
labelStyle: theme.textTheme.headline6,
suffixText: suffixText ?? '',
border: OutlineInputBorder(
borderSide:
BorderSide(color: theme.textTheme.bodyText2.color, width: 2),
),
hintText: '0.0',
floatingLabelBehavior: FloatingLabelBehavior.always),
validator: (value) {
if (value.isEmpty) {
return 'Please enter some text';
}
return null;
},
onChanged: (String text) => onChange(text),
);
Ideally in Flutter you cannot do this as both hintText and labelText behave in two different ways. labelText is shown as hintText as long as the user does not focus on it. As soon as the user clicks on the TextField, the labelText animates to a specific position whereas a hintText remains visible until the user types something.
So using labelText and hintText together, does not make any sense as the TextField will wipe of the hintText while animating the label.
However with some extra effort, you can use Stack widget to solve your problem.
Declare a class variable (a variable within the concerned class, outside any block of code) to store a TextEditingController.
TextEditingController _controller;
And initialize in your class' initState(),
_controller= TextEditingController();
Solution Code:
Container(
margin: EdgeInsets.all(20),
child: Stack(
children : <Widget>[
TextFormField(
autofocus: true,
textAlign: TextAlign.right,
decoration: InputDecoration(
enabledBorder: const OutlineInputBorder(
borderSide: const BorderSide(color: Color(0xff0E9447), width: 2.0),
),
focusedBorder: const OutlineInputBorder(
borderSide: const BorderSide(color: Color(0xff0E9447), width: 2.0),
),
labelText: AppStrings.email,
alignLabelWithHint: true,
hintStyle: TextStyle(color: AppColors.primaryColorLight),
),
),
(_controller.text=="")
?
Text(
AppStrings.email,
style: TextStyle(
color: Colors.grey
// Style it according to your requirement / To make it look like hintText
),
)
:
Container();
],
),
),
Basic Logic of the above code: If the TextField does not have any text then display the (hint) Text
widget else don't display anything.
There is a way around this.
Use the labelText property and set floatingLabelBehavior: FloatingLabelBehavior.never.
This way you will always see the hint and when the User clicks on the TextField, it goes away.