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.
Related
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();
I currently have this TextFormField with a hintText:
the goal is to add Units inside the TextFormField, regardless of whether the user is typing or not. It should kinda look like this:
How to achieve this?
Also, how to center the value?
Here's my current code for the TextFormField:
TextFormField(
decoration: InputDecoration(
hintText: '0.0',
contentPadding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 5.0),
filled: true,
fillColor: Colors.white24,
floatingLabelBehavior: FloatingLabelBehavior.never,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide: BorderSide.none,
),
counterText: '',
),
),
TheTextFormField decoration can a suffixText property
TextFormField(
controller: c,
// align to center
textAlign: TextAlign.center,
decoration: InputDecoration(
hintText: '0.0',
// show kg
suffixText: 'Kg',
)
Text can be centered using the textAlign property
One way is to use TextFormField and text inside row which is inside a container
something like this can help
Container(
child: Row(
children: [TextFormField(), Text('Kg')],
),
),
another way is that you can use
TextFormField(
decoration: InputDecoration(suffixText: 'Kg'),
),
but here the problem is that you will only get suffix text when the TextFormField is enabled, one workaround you can try to make it always visible is to use autovalidate property like
TextFormField(
autovalidateMode: AutovalidateMode.always,
decoration: InputDecoration(suffixText: 'Kg'),
),
I have not tested this autovalidateMode but it should work properly.
I am using the below code for the email field along with the email validator in flutter application, which is working fine until if the user gives the whitespace after entering the email in the textfield, which I am not able to trim using .trim(), how should I trim the whitespace if in case the user has entered it?
String emailValidator(String value) {
Pattern pattern =
r'^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';
RegExp regex = new RegExp(pattern);
if (!regex.hasMatch(value)) {
return 'Email format is invalid';
} else {
return null;
}
}
final email = TextFormField(
decoration: InputDecoration(
labelText: "Email",
labelStyle: TextStyle(color: Colors.black),
prefixIcon: Icon(
LineIcons.envelope,
color: Colors.black38,
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.black38),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.orange),
),
),
keyboardType: TextInputType.text,
style: TextStyle(color: Colors.black),
cursorColor: Colors.black,
controller: emailInputController,
validator: emailValidator,
);
For Flutter 1.20.0 and highest:
TextFormField(
validator: (value),
inputFormatters: [
FilteringTextInputFormatter.deny(new RegExp(r"\s\b|\b\s"))
],
)
How about you prevent user input whitespace using 'inputFormatters and BlacklistingTextInputFormatter'?
TextFormField(
validator: _validateInput,
inputFormatters: [BlacklistingTextInputFormatter(
new RegExp(r"\s\b|\b\s")
)],
...
It can be done in two different ways.
1.Allowing only the email regex.
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(regex) // your email regex here
]
2.Denying the whitespace
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(r"\s\b|\b\s")
]
Note: If you want to deny some special characters use FilteringTextInputFormatter.deny()
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.deny(regex) // your regex here
]
you should use inputFormatter and don't allow any white space.
TextFormField(
decoration: InputDecoration(
labelText: "Email",
labelStyle: TextStyle(color: Colors.black),
prefixIcon: Icon(
LineIcons.envelope,
color: Colors.black38,
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.black38),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.orange),
),
),
keyboardType: TextInputType.text,
style: TextStyle(color: Colors.black),
cursorColor: Colors.black,
controller: emailInputController,
validator: emailValidator,
inputFormatters: [WhitelistingTextInputFormatter(RegExp(r'[a-zA-Z0-9]'))],
)
I would like to implement a Text Widget whose label works in a similar way to the TextField below. (I don't expect I can input a value to the Text Widget. The Text Widget will be only for showing a text.) Could anyone teach me this?
If the value is '' (empty string), then show "Output" in the box.
If the value is not empty, then show "Output" on the border.
TextField sample
Without value:
With value:
TextField(
keyboardType: TextInputType.number,
style: Theme.of(context).textTheme.display1,
decoration: InputDecoration(
labelText: 'Input',
labelStyle: Theme.of(context).textTheme.display1,
errorText: _hasInputError ? 'Invalid number entered' : null,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(0.0),
),
),
),
TextFormField(
keyboardType: TextInputType.number,
style: Theme.of(context).textTheme.bodyText1,
decoration: InputDecoration(
labelText: 'Input',
hintText: "Input",
labelStyle: Theme.of(context).textTheme.bodyText1,
errorText: _hasInputError ? 'Invalid number entered' : null,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(0.0),
),
),
),
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.