Flutter SvgPicture in TextField not adapting color - flutter

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;
}

Related

How to make the icon in TextFormField enabled in code?

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;
});
},
),

Flutter - different colors for initial value and user input in textfield

Basically what I'm trying to do is to supply an initial value (grey) to a text field and once the user clicks the text field, the initial value is automatically cleared and the user input should be black. Currently my code is like this.
TextEditingController _controller;
FocusNode _focusNode;
#override
void initState() {
super.initState();
_controller = TextEditingController(text: 'Search');
_focusNode = FocusNode()..addListener(_onFocus);
}
#override
void dispose() {
_focusNode.dispose();
_controller.dispose();
super.dispose();
}
void _onFocus() {
if (_focusNode.hasFocus) _controller.clear();
}
Widget _buildSearchBox() {
return CupertinoTextField(
controller: _controller,
focusNode: _focusNode,
style: TextStyle(
fontSize: 17,
color: _focusNode.hasFocus
? CupertinoColors.black
: CupertinoColors.systemGrey,
),
decoration: BoxDecoration(
color: CupertinoColors.systemGrey6,
),
);
}
I know it doesn't work because: (a) everytime the user types something, does something else and clicks the text field again, his input is cleared (b) I hope only the initial value is grey, but once the user does something else, his input also becomes grey.
Can anyone help me with it? Thanks.
From what I understood from the question, one way you can do this is something like this
FocusNode _focusNode;
#override
void initState() {
super.initState();
_focusNode = FocusNode()..addListener(_onFocus);
}
void _onFocus() {
setState((){});
}
Widget _buildSearchBox() {
return CupertinoTextField(
placeholder: "Search",
focusNode: _focusNode,
style: TextStyle(
fontSize: 17,
color: _focusNode.hasFocus
? CupertinoColors.black
: CupertinoColors.systemGrey,
),
decoration: BoxDecoration(
color: CupertinoColors.systemGrey6,
),
);
}
#override
void dispose() {
_focusNode.dispose();
super.dispose();
}
Add a placeholder field see you cannot style it, individually as
It is a lighter colored placeholder hint that appears on the first line of the text field when the text entry is empty.
Defaults to having no placeholder text.The text style of the placeholder text matches that of the text field's main text entry except a lighter font weight and a grey font color.
CupertinoTextField(
placeholder: "Enter Email", //Add this and your work is done
controller: _controller,
focusNode: _focusNode,
style: TextStyle(
fontSize: 17,
color: _focusNode.hasFocus
? CupertinoColors.black
: CupertinoColors.systemGrey,
),
decoration: BoxDecoration(
color: CupertinoColors.systemGrey6,
),
);

How to change TextFiled widget background color when focus

I have a TextField widget which has default background color red.
I want to change the background color to blue when the TextFiled is focused. But I can't do that.
There are three relative properties about the color I have tried.
filled: true,
fillColor: Colors.red,
focusColor: Colors.blue,
The result is only filled is set to true, the fillColor worked and the focusColor never work.
Can you tell me what to do?
You need to use a FocusNode on your TextField and a color variable to change the color:
Declarations
FocusNode _textFieldFocus = FocusNode();
Color _color = Colors.red;
#override
void initState() {
_textFieldFocus.addListener((){
if(_textFieldFocus.hasFocus){
setState(() {
_color = Colors.blue;
});
}else{
setState(() {
_color = Colors.red;
});
}
});
super.initState();
}
Widget
TextField(
decoration: InputDecoration(
fillColor: _color,
filled: true
),
focusNode: _textFieldFocus,
),

Flutter: How to change TextFormField prefixIcon not focus color by ThemeData?

Flutter: I could change the TextFormField prefixIcon focus color by setting Theme.accentColor, but can't find any way to change the prefixIcon color when not focus.
Use FocusNode Class, this will keep a track of when you have the focus on that particular TextFormField.
Note: Make sure you assign different FocusNode object to different TextFormField() if you have multiple class.
Here is your solution:
FocusNode _focusNode;
#override
void dispose() {
super.dispose();
_focusNode.dispose();
}
#override
void initState() {
super.initState();
_focusNode = new FocusNode();
_focusNode.addListener(_onOnFocusNodeEvent);
}
_onOnFocusNodeEvent() {
setState(() {
// Re-renders
});
}
TextFormField(
focusNode: _focusNode
decoration: InputDecoration(
border: InputBorder.none,
prefixIcon: Padding(
padding: EdgeInsets.all(0.0),
child: Icon(
Icons.search,
color: this.getPrefixIconColor(),
) // icon is 48px widget.
)
)
)
//This will change the color of the icon based upon the focus on the field
Color getPrefixIconColor(){
return _focusNode.hasFocus ? Colors.black : Colors.grey
}
Let me know if that helps. Thanks

(Flutter) TextFormField Change labelColor on Focus

I am trying to change my labelText color when focused. I can change the text color but not when focused.
I have tried all the hint text colors and label text colors, but nothing helps.
Container(
padding: EdgeInsets.fromLTRB(15, 10, 15, 0),
child: TextFormField(
cursorColor: Colors.lightGreen,
keyboardType: TextInputType.phone,
decoration: InputDecoration(
labelText: 'Phone Number',
hintText: 'Enter a Phone Number',
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Colors.lightGreen
)
),
border: OutlineInputBorder(
borderSide: BorderSide()
),
)
),
),
Here are images of what is happening:
You'd need to have a way determine its focus state and then create a conditional for its color based off of that. This is where a focusNode would be helpful. Construct a new FocusNode off the widget creation, use that as the focusNode property in the TextFormField. Then in color property of the TextStyle property of the TextFormField you could add something like:
FocusNode myFocusNode = new FocusNode();
...
return TextFormField(
focusNode: myFocusNode,
decoration: InputDecoration(
labelText: 'test',
labelStyle: TextStyle(
color: myFocusNode.hasFocus ? Colors.blue : Colors.black
)
),
);
EDIT : Just a quick note, you'll probably need to make sure this is in a StatefulWidget and then add a listener to the focusNode you created and call setState on any events on that focusNode. Otherwise you wont see any changes.
The Summary
You might want to check out Flutter Cookbook's Focus and text fields recipe.
Essentially, we have to:
Create a FocusNode property.
Add initialization and disposal to it.
Add it to the TextFormField.
Add a focus request on every tap on the TextFormField.
1. Create a FocusNode property
class CustomTextFormFieldState extends State<CustomTextFormField> {
FocusNode _focusNode;
...
2. Add initialization and disposal to it
#override
void initState() {
super.initState();
_focusNode = FocusNode();
}
#override
void dispose() {
_focusNode.dispose();
super.dispose();
}
3. Add it to the TextFormField
#override
Widget build(BuildContext context) {
return TextFormField(
focusNode: _focusNode,
...
4. Add a focus request on every tap on the TextFormField
Don't forget to use setState:
void _requestFocus(){
setState(() {
FocusScope.of(context).requestFocus(_focusNode);
});
}
Add the method to the TextFormField's onTap property:
#override
Widget build(BuildContext context) {
return TextFormField(
focusNode: _focusNode,
onTap: _requestFocus,
...
Use themes, this would only have to be done once in a central place:
inputDecorationTheme: InputDecorationTheme(
floatingLabelStyle: TextStyle(color: Colors.blue),
),
A quick solution is changing the primarySwatch from the theme of the Widget MaterialApp. The only disadvantage is that a Material Color is required.
I solve this problem with a Focus widget. First I defined a Color-Variable for each Field:
final _lowColor = Colors.amber[50]; // use your own colors
final _highColor = Colors.amber[200];
Color _field1Color = _lowColor;
Color _field2Color = _lowColor;
...
Then I wrapped each TextFormField with a Focus Widget and change the fieldColor:
child: Focus(
onFocusChange: (hasFocus) {
setState(() => _field1Color = hasFocus ? _highColor : _lowColor);
},
child: TextFormField(
...
color: _field1Color,
...
),
),
),
Here is a quick method without using stateful widget
return Theme( // 1) wrap with theme widget
data: Theme.of(context).copyWith(primaryColor: //2) color you want here)
child: TextFormField(
focusNode: myFocusNode,
decoration: InputDecoration(
labelText: 'test',
),
),
);
https://api.flutter.dev/flutter/material/InputDecoration/labelStyle.html
labelStyle: MaterialStateTextStyle.resolveWith((Set<MaterialState> states) {
final Color color = states.contains(MaterialState.focused)
? Colors.pink
: Colors.orange;
return TextStyle(color: color);
}),
for active/click
floatingLabelStyle: TextStyle(color: Colors.yellow),
for inactive
labelStyle: TextStyle(color: Colors.black),
below is complete example
TextField(
decoration: InputDecoration(
hintText: 'Verify Password',
focusColor: appColor,
labelText: "Verify Password",
labelStyle: TextStyle(color: Colors.black),
floatingLabelStyle: TextStyle(color: appColor),
floatingLabelBehavior: FloatingLabelBehavior.always
),
cursorColor: appColor,
)
Update
As mentioned by Guilherme in the comment, the later version of Flutter uses different logic to get the color
Color _getActiveColor(ThemeData themeData) {
if (isFocused) {
return themeData.colorScheme.primary;
}
return themeData.hintColor;
}
Source
You will now need to set it from the colorScheme instead
ThemeData.dark().copyWith(
colorScheme: ColorScheme.dark(
primary: activeColor,
),
)
Original answer
After digging the source code for the InputDecorator used to determine the label color, here's what I found.
TextStyle _getFloatingLabelStyle(ThemeData themeData) {
final Color color = decoration.errorText != null
? decoration.errorStyle?.color ?? themeData.errorColor
: _getActiveColor(themeData);
final TextStyle style = themeData.textTheme.subtitle1.merge(widget.baseStyle);
return style
.copyWith(color: decoration.enabled ? color : themeData.disabledColor)
.merge(decoration.labelStyle);
}
Color _getActiveColor(ThemeData themeData) {
if (isFocused) {
switch (themeData.brightness) {
case Brightness.dark:
return themeData.accentColor;
case Brightness.light:
return themeData.primaryColor;
}
}
return themeData.hintColor;
}
In short, to change the label color, set the primaryColor light theme or accentColor for dark theme.
Another tip: To change the label color while it's not focused, set hintColor.
ThemeData.dark().copyWith(
primaryColor: Colors.red,
accentColor: Colors.white,
hintColor: Colors.pink,
)
One more clean way to do it with styles (you can add styles to the main theme and use for dark \ light modes)
TextFormField(
decoration: InputDecoration(
labelText: "some label",
labelStyle: const TextStyle(color: Colors.grey),
floatingLabelStyle: const TextStyle(color: Colors.blueAccent),
),),
you can also use labelStyle when the text field is in focus and if the text field is erroneous (caused by not following the validation)
labelText: 'Password',
labelStyle: TextStyle(
color: Colors.black54,
),
//when error has occured
errorStyle: TextStyle(
color: Colors.black,
),
I solved the problem using a StatefulWidget and Focus widget.
I use StatefulWidget because you need to use setState to notify the color change when focus on input
class InputEmail extends StatefulWidget {
#override
_InputEmailState createState() => _InputEmailState();
}
class _InputEmailState extends State<InputEmail> {
Color _colorText = Colors.black54;
#override
Widget build(BuildContext context) {
const _defaultColor = Colors.black54;
const _focusColor = Colors.purple;
return Container(
padding: EdgeInsets.symmetric(vertical: 15),
child: Focus(
onFocusChange: (hasFocus) {
// When you focus on input email, you need to notify the color change into the widget.
setState(() => _colorText = hasFocus ? _focusColor : _defaultColor);
},
child: TextField(
// Validate input Email
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
hintText: 'example#domain.com',
labelText: 'Email',
labelStyle: TextStyle(color: _colorText),
// Default Color underline
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.black26),
),
// Focus Color underline
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.purple),
),
icon: Icon(
Icons.mail,
color: Colors.deepPurpleAccent,
),
),
),
),
);
}
}
If You want to change the primary color. Just simply define add the primaryColor of the Widget MaterialApp
const appPrimaryColor = Color(0xFF746DF7);
ThemeData theme() {
return ThemeData(
scaffoldBackgroundColor: Colors.white,
fontFamily: "Inter",
appBarTheme: appBarTheme(),
textTheme: textTheme(),
inputDecorationTheme: inputDecorationTheme(),
visualDensity: VisualDensity.adaptivePlatformDensity,
primaryColor: appPrimaryColor // <------ HERE
);
}
MaterialApp(
title: 'Flutter Demo',
theme: theme(), // <------ HERE
home: SplashScreen(),
routes: routes,
)
You can wrap the textfield with Theme and set the primary color to whatever you want the label color to be
There is a 'lableStyle' in 'decoration', just like:
labelText: 'Description',
labelStyle: TextStyle(
color: Colors.lightBlueAccent,
)),
There is a floatingLabelStyle parameter in the InputDecoration, you can use it like this:
decoration: InputDecoration(
labelText: "label",
hintText: "hint",
labelStyle: GoogleFonts.roboto(
color: color.labelColor,
),
floatingLabelStyle: GoogleFonts.roboto(
color: color.defaultGreen,
),),