Bug in TextField in flutter - flutter

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.

Related

How to freeze label in TextField?

I have label in the top left corner of my TextField. I want the user to be able to see the hint always (and after that he filled the form), but it disappears when I tap.
#override
Widget build(BuildContext context) {
return TextField(
decoration: InputDecoration(
floatingLabelBehavior: FloatingLabelBehavior.never,
label: Align(
alignment: Alignment.topLeft,
child: Text(
_text,
textAlign: TextAlign.left,
style: const TextStyle(fontSize: 15),
)),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
borderRadius: BorderRadius.all(Radius.circular(10))),
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
borderRadius: BorderRadius.all(Radius.circular(10)),
)));
}
You can achieve this behavior by using the hintText property in the InputDecoration class. The hintText property provides a text hint that is displayed in the input field when it is empty. The hint text disappears as soon as the user starts typing and reappears if the text field is emptied. Here's the updated code:
#override
Widget build(BuildContext context) {
return TextField(
decoration: InputDecoration(
hintText: _text,
floatingLabelBehavior: FloatingLabelBehavior.never,
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
borderRadius: BorderRadius.all(Radius.circular(10))
),
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
borderRadius: BorderRadius.all(Radius.circular(10)),
)
),
);
}
The material design suggest to use the labelText property on the InputDecoration. Maybe you have already tried and dismissed it.. but I'm checking just in case... have you tried that?
This will be the typical outcome:
If you do not want to go with hintText, you can make a stack where the first child is the ’TextField’ and the other is Positioned for your text.

Change prefix icon color of text form field in flutter on clicking the field

I have a name form field in flutter app. There's a prefix icon in it. When I click the form field the color of icon changes to blue, rather I want to change it to green. How can I do that, can anyone please guide me? This is its code :
TextFormField(
decoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.green, width: 2.0),
borderRadius: BorderRadius.circular(10.0),
),
prefixIcon: const Icon(Icons.person),
hintText: "Name",
border: OutlineInputBorder(borderRadius: BorderRadius.circular(10)),
),
);
Flutter's way to go is to use resolveWith. You can check the current state to check if the text field is focused, shows an error, etc. And depending on that you set the color.
From the docs (https://api.flutter.dev/flutter/material/InputDecoration-class.html):
final ThemeData themeData = Theme.of(context);
return Theme(
data: themeData.copyWith(
inputDecorationTheme: themeData.inputDecorationTheme.copyWith(
prefixIconColor:
MaterialStateColor.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.focused)) {
return Colors.green;
}
if (states.contains(MaterialState.error)) {
return Colors.red;
}
return Colors.grey;
}),
)),
child: TextFormField(
initialValue: 'abc',
decoration: const InputDecoration(
prefixIcon: Icon(Icons.person),
),
),
);
Use Theme color to change then define the focus node to determine when the field is on focus in order to apply these color changes
...
FocusNode _fieldNode = FocusNode(); //<-Define this then
...
TextFormField(
decoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.green, width: 2.0),
borderRadius: BorderRadius.circular(10.0),
),
prefixIcon: Icon(Icons.person,
color: _fieldNode.hasFocus
? Theme.of(context).primaryColor
: Colors.purple)),
hintText: "Name",
border: OutlineInputBorder(borderRadius: BorderRadius.circular(10)),
),
);

backspace text field flutter on Android devices not working

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();

Flutter Forms Validation on change

Hey maybe someone can help me to figure out how implement proper form validation in Flutter.
So basically in InputDecoration we have
decoration: InputDecoration(
// focusedBorder: OutlineInputBorder(
// borderSide: BorderSide(color: Colors.white, width: 3.0),
// ),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.red, width: 3.0),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.greenAccent, width: 3.0),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.red, width: 3.0),
),
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white, width: 3.0),
),
labelText: 'Email',
// errorText: !_isValid ? "Invalid Email" : null,
labelStyle: TextStyle(color: Colors.white),
prefixIcon: Padding(
padding: const EdgeInsets.only(top: 10, left: 13),
child: FaIcon(
FontAwesomeIcons.at,
color: Colors.white,
size: 25,
),
),
),
So problem is that I can't understand how to set regular border on form when it is not touched , than when it's touched , on each input it has to validate input and set error if not valid. I know that on TextFormField i can pass onchange function and do the validation
onChanged: (value) {
if (value.isEmpty || !value.contains('#')) {
setState(() {
_isValid = false;
});
print('invalid');
} else {
setState(() {
_isValid = true;
});
}
with this approach I have issue, first I have to set initial value of _isValid and in this case when form is opened and not touched it's already are enabled or with error depending on initial value of _isValid.
I came from web and worked with Angular and there we have reactive forms, maybe someone explain how to achieve similar behavior in flutter?
validator: (value) {
if (enter code herevalue.isEmpty || !value.contains('#')) {
return "incorrect format";
}
1 create a global form key
2 warp your widget inside a Form widget
3 pass your global key to the key parameter of your Form widget
4 and use this line on button click
5 _yourFormKey.CurrentState.Validate();

How to always show hint in text field not only when it is clicked in flutter?

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.