Reputation: 99
I need to restrict when the user types 1.. like this. i'm using text input form field. I need input like 1.23 with decimal input text formatter
Upvotes: 9
Views: 14055
Reputation: 369
This will allow any number, using the locale specific decimal separator (afaik always either ',' or '.'). The intl
package is used to get that separator.
import 'package:intl/intl.dart';
...
TextFormField(
inputFormatters: [
TextInputFormatter.withFunction((oldValue, newValue) {
var decimalSeparator = NumberFormat().symbols.DECIMAL_SEP;
var r = RegExp(r'^\d*(\' + decimalSeparator + r'\d*)?$');
return r.hasMatch(newValue.text) ? newValue : oldValue;
})
],
...
As an aside, the answers using FilteringTextInputFormatter
will work to validate initial input but will show strange behavior when trying to edit a valid number to an invalid one - some characters will get overwritten, others deleted.
As per the docs:
Consider using a different TextInputFormatter ... for accepting/rejecting new input based on a predicate on the full string. As an example, FilteringTextInputFormatter typically shouldn't be used with RegExps that contain positional matchers (^ or $) since these patterns are usually meant for matching the whole string.
Upvotes: 0
Reputation: 1557
you can also try decimal validation on form submit.
bool isValidDecimal(String value){
String regex = r'^[0-9]+[.]{1}[0-9]+$';
RegExp regExp = RegExp(regex);
return regExp.hasMatch(value);
}
Upvotes: 0
Reputation: 3602
As the user @ZaH mentioned, WhitelistingTextInputFormatter
has been deprecated as of Flutter 1.20, instead FilteringTextInputFormatter.allow()
should be used. Check out ZaH's answer here and give em an upvote. You can find the docs for the class and constructor.
TextFormField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r"\d+([\.]\d+)?")),
],
);
Here is what you need to do for your specific use case:
TextFormField(
inputFormatters: [
WhitelistingTextInputFormatter(RegExp(r"\d+([\.]\d+)?")),
],
);
You need to use TextInputFormatter
class. Specifically WhitelistingTextInputFormatter.
The above code only allows numbers of the pattern you provided in your question. Numbers with optionally any number of decimal digits with one decimal point allowed.
The r
prefix before the string as in r""
makes the string a raw string
. This prevents filtering and treatment of special characters within the string. From the docs:
Note the use of a raw string (a string prefixed with r) in the example above. Use a raw string to treat each character in a string as a literal character.
Here's a dissection of the regex pattern ^\d+([\.]\d+)?$
:
\d
digit -- allows digits from all languages.+
one or more occurrence.(PATTERN)?
zero or one occurrences -- this allows numbers without decimal dot/digits.[\.]
allows dot character -- the \ is used to escape it since it's a control character in regex.Upvotes: 5
Reputation: 600
With WhitelistingTextInputFormatter deprecated
TextField(
keyboardType: TextInputType.numberWithOptions(decimal: true),
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(RegExp(r'^\d+\.?\d*')),
], // Only numbers can be entered
),
Upvotes: 25
Reputation: 116
the answer from om-ha is correct, however for future reference, WhitelistingTextInputFormatter is deprecated in Flutter as of 1.20, now we should use FilteringTextInputFormatter.allow() instead.
or use FilteringTextInputFormatter.deny instead of BlacklistingTextInputFormatter if that is what you want.
above code should become:
TextFormField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r"\d+([\.]\d+)?")),
],
);
Upvotes: 2
Reputation: 15073
We can create our own TextInputFormatter
.
Check this
import 'package:flutter/services.dart';
class DecimalTextInputFormatter extends TextInputFormatter {
@override
TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
final regEx = RegExp(r"^\d*\.?\d*");
String newString = regEx.stringMatch(newValue.text) ?? "";
return newString == newValue.text ? newValue : oldValue;
}
}
Usage:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: FirstPage(),
debugShowCheckedModeBanner: false,
);
}
}
class FirstPage extends StatefulWidget {
@override
_FirstPageState createState() => _FirstPageState();
}
class _FirstPageState extends State<FirstPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: TextField(
inputFormatters: [DecimalTextInputFormatter()],
),
),
);
}
}
Upvotes: 15