I have a TextField widget to add players in a List. But I want the keyboard to stay focus when I add players, and on submit, my keyboard keeps loosing focus.. Any Idea ?
Here is my TextField widget:
TextField(
textCapitalization: TextCapitalization.words,
onChanged: (val) => playerName = val.trim(),
onSubmitted: (val) {
if (playerName != null && playerName != '') {
Provider.of<PlayerProvider>(context, listen: false).addPlayer(playerName);
HapticFeedback.lightImpact();
}
},
maxLength: 19,
autocorrect: false,
decoration: new InputDecoration(
counterText: "",
border: new OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: const BorderRadius.all(
const Radius.circular(30.0),
),
),
filled: true,
contentPadding: EdgeInsets.symmetric(vertical: 0, horizontal: 20),
hintStyle: GoogleFonts.rubik(color: Colors.grey[500], fontWeight: FontWeight.bold),
hintText: AppLocalizations.of(context).translate('player_selection_page_hint'),
fillColor: Colors.white),
)
By the way, the autofocus: true works but it kinda unFocus the keyboard and give the focus back instantly... So it's not nice to watch. So If you have another idea please.
I think you should try using FocusNode.
class MyCustomForm extends StatefulWidget {
#override
_MyCustomFormState createState() => _MyCustomFormState();
}
// Define a corresponding State class.
// This class holds data related to the form.
class _MyCustomFormState extends State<MyCustomForm> {
// Define the focus node. To manage the lifecycle, create the FocusNode in
// the initState method, and clean it up in the dispose method.
FocusNode myFocusNode;
#override
void initState() {
super.initState();
myFocusNode = FocusNode();
}
#override
void dispose() {
// Clean up the focus node when the Form is disposed.
myFocusNode.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return TextField(
focusNode: myFocusNode
textCapitalization: TextCapitalization.words,
onChanged: (val) => playerName = val.trim(),
onSubmitted: (val) {
if (playerName != null && playerName != '') {
Provider.of<PlayerProvider>(context, listen: false).addPlayer(playerName);
HapticFeedback.lightImpact();
}
myFocusNode.requestFocus();
},
maxLength: 19,
autocorrect: false,
decoration: new InputDecoration(
counterText: "",
border: new OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: const BorderRadius.all(
const Radius.circular(30.0),
),
),
filled: true,
contentPadding: EdgeInsets.symmetric(vertical: 0, horizontal: 20),
hintStyle: GoogleFonts.rubik(color: Colors.grey[500], fontWeight: FontWeight.bold),
hintText: AppLocalizations.of(context).translate('player_selection_page_hint'),
fillColor: Colors.white),
);
}
}
Well, you can go with FocusNode.
But I have a workaround for this.
I usually set the
autovalidate:true
and in validator always return some text.
So whenever the user clicks on the textfield it never loses the focus.
Thus the flutter always keeps the focus on the text field.
But for this, you've to use TextFormField.
But the correct way is to go with FocusNode.
Here's the Code.
TextFormField (
autovalidate : true
validator: (value) {
return '';
},
textCapitalization: TextCapitalization.words,
onChanged: (val) => playerName = val.trim(),
onSaved: (val) {
if (playerName != null && playerName != '') {
Provider.of<PlayerProvider>(context, listen: false).addPlayer(playerName);
HapticFeedback.lightImpact();
}
},
maxLength: 19,
autocorrect: false,
decoration: new InputDecoration(
counterText: "",
border: new OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: const BorderRadius.all(
const Radius.circular(30.0),
),
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: const BorderRadius.all(
const Radius.circular(30.0),
),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: const BorderRadius.all(
const Radius.circular(30.0),
),
),
filled: true,
contentPadding: EdgeInsets.symmetric(vertical: 0, horizontal: 20),
hintStyle: GoogleFonts.rubik(color: Colors.grey[500], fontWeight: FontWeight.bold),
hintText: AppLocalizations.of(context).translate('player_selection_page_hint'),
fillColor: Colors.white),
)
and then you can use this to call the onSaved method
_formKey.currentState.save(); // And it will call the onSaved method
Here the _formKey
Form(
key: _formKey,
child: Widget(),
),
Wrap the whole widget tree where your textformfield is present.
Related
I have TextFormField and I want to change color of border and labelText, how can I do that?
That's how it looks now, and I want to change blue to purple.
(https://im.ge/i/FImpIh)
import 'package:flutter/material.dart';
class InputTextFormField extends StatefulWidget {
final String labelText;
TextEditingController? controller;
InputTextFormField({Key? key, required this.labelText, required this.controller});
#override
_InputTextFormFieldState createState() => _InputTextFormFieldState();
}
class _InputTextFormFieldState extends State<InputTextFormField> {
#override
Widget build(BuildContext context) {
return TextFormField(
decoration: InputDecoration(
alignLabelWithHint: true,
labelText: widget.labelText,
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12.0)),
),
),
validator: (value) => value!.isEmpty ? 'Please, fill this field.' : null,
controller: widget.controller,
);
}
You will need to define a focusedBorder inside TextField for the border color and labelStyle for label color
class _InputTextFormFieldState extends State<InputTextFormField> {
FocusNode myFocusNode = FocusNode();
#override
void initState() {
super.initState();
myFocusNode.addListener((){
setState((){});
});
}
#override
void dispose() {
myFocusNode.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return TextFormField(
focusNode: myFocusNode,
decoration: InputDecoration(
alignLabelWithHint: true,
labelText: widget.labelText,
labelStyle: TextStyle(
color: myFocusNode.hasFocus ? Colors.purple : Colors.black
),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12.0)),
),
focusedBorder: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12.0)),
borderSide: BorderSide(color: Colors.purple, width: 0.5),
)
),
validator: (value) => value!.isEmpty ? 'Please, fill this field.' : null,
controller: widget.controller,
);
}
}
Use the decoration parameter with an InputDecoration : https://api.flutter.dev/flutter/material/InputDecoration-class.html
Like this
TextFormField(
decoration: InputDecoration(
labelStyle: TextStyle(color: Colors.purple), /// Your parameters for the label
border: OutlineInputBorder(borderSide: BorderSide(color: Colors.purple)), /// Your parameters for the border
),
...
)
InputDecoration already has properties for that
InputDecoration(
alignLabelWithHint: true,
labelText: widget.labelText,
labelStyle: //TextStyle,
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12.0)),
borderSide: BorderSide(color: color, width: 2),//border Color
),
),
i have a form pages contain a widget that will return various widget form according to the api parameters, for example: the parameters is 'type': 'text_box so the widget will return TextField widget if the parameters is 'type': 'dropdown_box' it will return dropdown widget.
This is just an example for what widget i make, the real problem is in the TextField widget because everytime i input in the field then press any other form widget(not pressing the complete button on textfield) and select the value it will return the focus to the TextField before if i press complete button the focus is neutral again what i want is when i press another widget the focus from the TextField is clear.
code
TextFormField(
minLines: widget.minLines,
inputFormatters: [
if (widget.isPrice)
MoneyInputFormatter(
thousandSeparator: ThousandSeparator.Period,
mantissaLength: 0,
),
],
controller: widget.controllerName,
onTap: () {
widget.onTap();
},
enabled: widget.enabled,
obscureText: widget.isObsecure,
style: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.w400,
color: (widget.textColor != null)
? widget.textColor
: widget.enabled
? Colors.black
: Colors.black38,
),
keyboardType: widget.keyboardType,
maxLines: widget.maxLines,
decoration: InputDecoration(
isDense: true, //remove default padding
fillColor:
widget.inputColor ?? Constants.colorAppointmentTextInput,
filled: true, // activate bg color
// hintText: widget.hintText,
hintText: widget.placeholder ?? 'Masukan ' + widget.hintText,
hintStyle: TextStyle(
fontSize: 14.0,
color: (widget.textColor != null)
? widget.textColor
: widget.enabled
? Colors.black54
: Colors.black38,
),
prefix: widget.prefix,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(
color: Constants.colorAppointmentBorderInput,
width: 0.5)),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(
color: Constants.colorAppointmentBorderInput,
width: 0.5)),
disabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(
color: Constants.colorAppointmentBorderInput,
width: 0.5)),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide:
BorderSide(color: Constants.redTheme, width: 0.5),
),
suffixIcon: widget.suffixIcon),
validator: (value) {
if (value.isEmpty) {
return 'Please enter some text';
}
return null;
},
),
this is what i mean the widget will return widget according to the api
#override
Widget build(BuildContext context) {
if (widget.questionType == 'text_box') {
return TextFild();
} else if (widget.questionType == 'dropdown') {
return Dropdown();
} else if (widget.questionType == 'radio') {
return radioType();
}
}
Add this Line :
FocusScope.of(context).requestFocus(FocusNode());
if keyboard on it will make it off , if it's off it will make it on .
You could use a focus node:
myFocusNode = FocusNode()
Add it to your TextFormField:
TextFormField(
focusNode: myFocusNode,
...
);
When an event that you want to unfocus the text field occurs, like tapping some other button etc. use:
myFocusNode.unfocus();
Make sure to dispose of the FocusNode in your dispose method:
#override
void dispose() {
myFocusNode.dispose();
//...
super.dispose();
}
You can use FocusNode.
Add it to TextformField.
TextFormField(
focusNode: focusNode,
...
);
Call focusNode.unfocus(); on onFieldSubmitted, onSaved. In your case on click action when you show your dropdown.
My requirement is I have 2 textfield widgets, when I click on first text field widget I need to change the label text color matching to cursor & border color. Same way when I click on 2nd text field, same behavior expected. How to achieve this.
Below is my code what I have tried so far:
Padding(
padding: const EdgeInsets.only(left: 32.0, right: 32.0),
child: TextField(
cursorColor: Color(0xFFD9A506),
decoration: new InputDecoration(
labelText: 'Username',
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Color(0xFFD9A506), style: BorderStyle.solid)),
enabledBorder: const UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xFF919191)),
),
labelStyle: new TextStyle(color: Color(0xFF919191)),
),
onChanged: (value) {
userName = value;
setState(() {
if (!userName.isEmpty && !password.isEmpty) {
isTextFiledFocus = true;
} else {
isTextFiledFocus = false;
}
});
},
),
),
Padding(
padding:
const EdgeInsets.only(top: 38.0, left: 32.0, right: 32.0),
child: TextField(
cursorColor: Color(0xFFD9A506),
obscureText: isHidePassword,
enableSuggestions: false,
autocorrect: false,
decoration: new InputDecoration(
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Color(0xFFD9A506),
style: BorderStyle.solid)),
labelText: 'Password',
suffixIcon: IconButton(
//eye icon
color: Color(0xFF919191),
onPressed: () {
//for keyboard to hide
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) {
currentFocus.unfocus();
}
//for keyboard to hide
setState(() {
isHidePassword = !isHidePassword;
});
},
icon: Icon(isHidePassword
? Icons.visibility
: Icons.visibility_off)), //eye icon
enabledBorder: const UnderlineInputBorder(
borderSide: BorderSide(color: Color(0xFF919191)),
),
labelStyle: new TextStyle(color: Color(0xFF919191)),
),
onChanged: (value) {
password = value;
setState(() {
if (!userName.isEmpty && !password.isEmpty) {
isTextFiledFocus = true;
} else {
isTextFiledFocus = false;
}
});
}),
),
You can use FocusNode with listener to change the label color. We just need to update the UI when focus is changed. You can also change the label text the same way.
final FocusNode focusNode1 = FocusNode();
final FocusNode focusNode2 = FocusNode();
#override
void initState() {
super.initState();
focusNode1.addListener(() {
setState(() {});
});
focusNode2.addListener(() {
setState(() {});
});
}
And assign focuse node on TextFiled
TextField(
cursorColor: Color(0xFFD9A506),
focusNode: focusNode1,
decoration: InputDecoration(
labelStyle: TextStyle(
color: focusNode1.hasFocus
? Color(0xFFD9A506)
: Color(0xFF919191)),
labelText: "UserName",
Do the same for next TextFiled.
How do I restrict my user from using space in textfield by automatically removing that space when the user finish typing?
For example, if the user type King of Light, it will apply as KingofLight after he/she steps away from the textfield.
TextFormField(
initialValue: nickname != null
? nickname
: current_user.nickname,
decoration: InputDecoration(
border: new OutlineInputBorder(
borderSide: new BorderSide(color: Colors.grey),
borderRadius: BorderRadius.circular(6),
),
focusedBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Colors.grey, width: 1.0),
borderRadius: BorderRadius.circular(6),
),
enabledBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Colors.grey, width: 1.0),
borderRadius: BorderRadius.circular(6),
),
hintText: 'Empty',
hintStyle: TextStyle(
color: Colors.grey[400],
fontSize: 20,
//fontWeight: FontWeight.bold,
),
),
style: TextStyle(
fontSize: 20,
// fontWeight: FontWeight.bold,
),
validator: (val) => val.length < 2
? 'Enter a nickname 2+char long'
: null,
onChanged: (val) {
val = val.replaceAll(' ', '');
setState(() => nickname = val);
},
),
please help me! thank you!
Text field which does not allow spaces, using RegExp. As below-
TextFormField(
inputFormatters: [
if (denySpaces)
FilteringTextInputFormatter.deny(
RegExp(r'\s')),
])
Above solution worked for me, to block space from keyboard.
One way you do this is like this using TextEditingController and can call formatNickname() as per your use case.
class _MyWidgetState extends State<MyWidget>{
FocusNode node = new FocusNode();
TextEditingController tc = TextEditingController();
#override
void initState(){
node.addListener((){
if(!node.hasFocus){
formatNickname();
}
});
super.initState();
}
void formatNickname(){
tc.text = tc.text.replaceAll(" ", "");
}
#override
Widget build(BuildContext context) {
return Column(
children: [
TextFormField(
focusNode: node,
controller: tc,
),
TextFormField(),
RaisedButton(
child: Text('Format'),
onPressed: (){
formatNickname();
},
),
],
);
}
}
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.