I have set a color to an icon in a TextFormField, but the color only comes when the TextFormField is focused.
How do I set it so that upon a setState() the icon stays 'focused' or colored?
try this:
bool _textIsEmpty = true;
TextEditingController _controller= TextEditingController();
... // rest of your code
TextField(
controller: _controller,
decoration: InputDecoration(
icon: Icon(
Icons.abc,
color: _textIsEmpty ? Colors.transparent : Colors.pink,
),
),
onChanged: (value) {
setState(() {
_textIsEmpty = value.isEmpty;
});
},
),
Related
When I set the TextField.prefixIcon property to an Icon(Icons.example) widget, the color of the icon automatically adapts according to the state of the TextField (enabled, focussed, ...).
Now, I got an Icon Pack with svg files that I want to use within the TextField. I am using flutter_svg to show them like that:
TextFormField(
decoration: InputDecoration(
hintText: "Password",
prefixIcon: SvgPicture.asset(
AppIcons.lock,
),
),
),
Now, how can I achieve the automatic color adaption with SvgPicture?
you need to resolve it manually :
FocusNode _focusNode = FocusNode();
bool _enabled = true;
#override
Widget build(BuildContext context) {
return TextFormField(
focusNode: _focusNode,
enabled: _enabled,
decoration: InputDecoration(
hintText: "password"
).copyWith(
prefixIcon: SvgPicture.asset(AppIcons.lock, color: _resolveColor())
),
);
}
Color _resolveColor(){
if (_focusNode.hasFocus){
return Colors.yellow;
}
if(!_enabled){
return Colors.white;
}
if (!_form.valid){
return Colors.red;
}
return Colors.grey;
}
Whenever I am defining the obscureText property of the TextFormField a suffix icon is automatically added at the end but after pressing it nothing happen,
The prefix icon is defined by me but the suffix icon is added automatically.
How to make that default icon interactive so that the password will be shown or hidden accordingly without adding our own suffix icon?
TextFormField(
style: TextStyle(color: Colors.black),
obscureText: true,
decoration: InputDecoration(
hintText: "Enter Password",
labelText: "Password",
prefixIcon: Icon(Icons.lock),
),
),
suffixIcon: IconButton(
onPressed: () => ShowHideFuncion(),
icon: Icon(Icons.YourIcon),
),
you need to make a variable in your widget of type bool (e.g. obscure). You then change the obscureText parameter from being true to being the variable you made.
Then add a suffixIcon with an IconButton() (see more here). In the IconButton()'s onPressed parameter set the variable to be not equal to the variable. (e.g. obscure = !obscure). There is a possibility you might need to make your widget a stateless widget and call setState(() => obscure = !obscure) if it doesn't update automatically.
The final code should look something like this:
Icon icon = Icon(Icons.visibility);
bool obscure = true;
TextFormField(
style: TextStyle(color: Colors.black),
obscureText: obscure,
decoration: InputDecoration(
hintText: "Enter Password",
labelText: "Password",
suffixIcon: IconButton(
onPressed: () {
setState(() {
if (obscure == true) {
obscure = false;
icon = Icon(Icons.visibility_off);
} else {
obscure = true;
icon = Icon(Icons.visibility);
}
});
},
icon: icon
),
),
),
This is because you are not changing the state of the obsecuretext.
In order to do that please declare variable of boolean type in main class.
bool isPassword = false;
Now in obscureText use the variable which you declared in main class as below.
`obscureText = isPasswordVisible`
Now make a Icon button to change the state of the boolean value by using set state as below.
suffixIcon: IconButton(
onPressed: () {
setState(() {
isPasswordVisible = !isPasswordVisible
});
},
icon: isPasswordVisible ? Icon(Icons.any_icon_you want) : Icon(Icons.any_Icon_you_want_to_display_when_obsecure_is_false)
),
Here's my code for the password field:
TextFormField(
obscureText: isObscure,
decoration: InputDecoration(
suffix: TextButton(
child: isPasswordObscure
? Text(
'Show',
style: TextStyle(color: Colors.grey),
)
: Text(
'Hide',
style: TextStyle(color: Colors.grey),
),
onPressed: () {
setState(() { isObscure = !isObscure; });
},
),
),
)
If I run it, the password field would look like this:
If you review my code, I only specified a text button and not an icon as the suffix. The visibility icon was added by Flutter Edge and when I click on it, it only changes its icon and does not unobscure or obscure the text field.
What I want to know is how do I change or remove the icon? And maybe also give it a callback so it knows what to do when I click on it.
The problem doesn't exist on mobile, only on browsers desktop Edge.
Edit:
I tried setting suffix and suffixIcon to null but the visibility icon is still showing.
Update: I've discovered that the problem only exists on MS Edge.
If you wants to turn off the visibility icon set onPressed: () {},
also if you want to remove the visibility icon form overview wrap it with opacity widget
Opacity(
opacity: 0.0,
child: textButton(),
Please find the below code sample to include the visibility option for the textField. by including a variable _isObscured in a stateful widget. we have implemented it with the auto obscure after 2 second delay.
Center(child: TextField(
obscureText: _isObscured,
decoration : InputDecoration(
suffix:InkWell(
onTap: (){
setState(() => this._isObscured =
!this._isObscured);
Future.delayed(Duration(seconds: 2), (){
setState(() => this._isObscured =
!this._isObscured);
});
},
child: Icon( Icons.visibility),
),
),
),
),
),
I found a solution:
// the magic function
void fixEdgePasswordRevealButton(FocusNode passwordFocusNode) {
passwordFocusNode.unfocus();
Future.microtask(() {
passwordFocusNode.requestFocus();
js.context.callMethod("fixPasswordCss", []);
});
}
// widget code
child: TextField(
onChanged: (_) async {
fixEdgePasswordRevealButton(passwordFocusNode);
},
focusNode: passwordFocusNode,
obscureText: true,
// end of index.html
window.fixPasswordCss = () => {
let style = document.createElement('style');
style.innerHTML = '::-ms-reveal { display: none; }';
document.head.appendChild(style);
}
</script>
</body>
Also posted on the relevant issue.
I want to change default colour of icon of TextFormField, which will also get changes on selection. There are few way to change colour but non of them works for me.
1. Set icon color
When changing icon colour directly as below the icon colour will not change when selected, below is the code of the same and screenshot which shows red colour when field is selected or not selected.
TextFormField(
maxLength: 15,
decoration: InputDecoration(
labelText: "USER NAME",
prefixIcon: IconTheme(data: IconThemeData(
color: Colors.redAccent
), child: Icon(Icons.email,))
),
onSaved: (username) => _username = username,
),
2. Leave it default
This will show grey colour when field is not selected and primary colour when field is selected. Below is the screenshot of the same. Here i want to change the colour of icon from grey to red and want to show primary colour on selection.
NOTE:- It will be good if we can do this using theme
The code below will generate the FocusNodes you need to manage the focus of your TextFormFields and do a setState when the focus changes from one field to another. We are just creating a list of focus nodes, listening to changes on each of them and assigning them to a field:
List<FocusNode> _focusNodes = [
FocusNode(),
FocusNode(),
FocusNode(),
FocusNode(),
];
#override
void initState() {
_focusNodes.forEach((node){
node.addListener(() {
setState(() {});
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
TextFormField(
focusNode: _focusNodes[0],
decoration: InputDecoration(
prefixIcon: Icon(Icons.email,
color: _focusNodes[0].hasFocus ? Theme.of(context).accentColor : Colors.grey,
),
),
),
TextFormField(
focusNode: _focusNodes[1],
decoration: InputDecoration(
prefixIcon: Icon(Icons.email,
color: _focusNodes[1].hasFocus ? Theme.of(context).accentColor : Colors.grey,
),
),
),
TextFormField(
focusNode: _focusNodes[2],
decoration: InputDecoration(
prefixIcon: Icon(Icons.email,
color: _focusNodes[2].hasFocus ? Theme.of(context).accentColor : Colors.grey,
),
),
),
],
);
}
If you want to change icon color at the time textFormField is selected,
change it according to below.
...
Theme(
child: Column(
children: <Widget>[
TextFormField(
maxLength: 15,
decoration: InputDecoration(
labelText: "USER NAME",
prefixIcon: Icon(Icons.email,)
),
onSaved: (username) => _username = username,
),
TextFormField(
maxLength: 15,
decoration: InputDecoration(
labelText: "EMAIL",
prefixIcon: Icon(Icons.email,)
),
onSaved: (usermail) => _useremail = usermail,
),
],
),
data: Theme.of(context)
.copyWith(primaryColor: Colors.redAccent,),
),
...
Conclusion:
Wrap all the textFormFields widgets with Theme widget and set data field as the color you want as a highlighter.
As you can see in the picture below, You can't change the default color of Icons in Textfields. The only solution for it is to create PR on flutter and change this method. 😄
I create a profile page and i have 4 textformfield. I want to on tap icon activate textformfield and focus at the same time. Now I need tap twice on icon and first activated field, secondly focused.
How to solve it?
My code:
class UserProfile extends StatefulWidget {
#override
_UserProfileState createState() => _UserProfileState();
}
class _UserProfileState extends State<UserProfile> {
FocusNode myFocusNode;
bool isEnable = false;
#override
void initState() {
super.initState();
myFocusNode = FocusNode();
}
#override
void dispose() {
myFocusNode.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: EdgeInsets.fromLTRB(40.0, 50.0, 20.0, 0.0),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Flexible(
child: TextFormField(
enabled: isEnable,
focusNode: myFocusNode,
),
),
IconButton(
icon: Icon(Icons.edit),
onPressed: () {
setState(() {
isEnable = true;
FocusScope.of(context).requestFocus(myFocusNode);
});
})
],
),
You should use autofocus: isEnable instead.
just do like below in your ontap
setState(() {
if(isEnable)
Future.delayed(const Duration(milliseconds: 10), ()
{FocusScope.of(context).requestFocus(myFocusNode);
});
isEnable = true;
});
in first time isEnable is false so focusing not call and just enabling work and in other times get focus too.
you can't focus widget until disabled and when you enabling widget. when you do focusing and enabling at same time in ui tread it's try focusing before enabling because of their rendering time.if you post some delay to focusing the problem get solving.
Try using readOnly instead of enabled in TextFormField
I faced similar issue when I had multiple TextFields to enable kinda PIN input. And some of that had to be dynamically enabled and disabled plus prevent users from entering value in the next field while they haven't finished the previous one. I've tried a lot of approaches and focusing field after some delay was not a way to go because I wanted the keyboard to always be available while entering. So I've took a crazy path and solved this next way:
onTap: () => _focusNodes[_currentLetterIndex].requestFocus()
where _focusNodes are for each letter and _currentLetterIndex is calculated programmatically during input (when finished letter 0 -> current becomes 1 and so on). As the result when user tried to tap on next field - it was automatically refocused to the current one which behaves like the next field is disabled.
An example of the full text field looks like this (don't pay attention to decorations etc.)
TextField(
key: ValueKey(index),
controller: _editingControllers[index],
onTap: () => _focusNodes[_currentLetterIndex].requestFocus(),
focusNode: _focusNodes[index],
textAlign: TextAlign.center,
showCursor: false,
maxLength: 2,
enableInteractiveSelection: false,
autocorrect: false,
enableSuggestions: false,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
height: 1.2,
decoration: TextDecoration.none),
decoration: InputDecoration(
fillColor: !_wordCompleted &&
!correct &&
_editingControllers[index].text.isNotEmpty
? const Color(0xFFFFEEF0)
: Colors.white,
filled: !correct,
counterText: "",
border: defaultInputBorder,
focusedBorder: !correct &&
!_wordCompleted &&
_editingControllers[index].text.isNotEmpty
? incorrectInputBorder
: focusedInputBorder,
enabledBorder: _wordCompleted
? focusedInputBorder
: correct
? correctInputBorder
: defaultInputBorder,
errorBorder: defaultInputBorder,
disabledBorder: _wordCompleted
? focusedInputBorder
: correct
? correctInputBorder
: defaultInputBorder,
contentPadding: const EdgeInsets.only(left: 2)),
),