I want only two digits after the decimal point in the flutter input.User can't add more than two digits after the decimal point.
16 Answers
Here you go! Hope it helps :)
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:math' as math;
void main() {
runApp(new MaterialApp(home: new MyApp()));
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Flutter"),
),
body: Form(
child: ListView(
children: <Widget>[
TextFormField(
inputFormatters: [DecimalTextInputFormatter(decimalRange: 2)],
keyboardType: TextInputType.numberWithOptions(decimal: true),
)
],
),
),
);
}
}
class DecimalTextInputFormatter extends TextInputFormatter {
DecimalTextInputFormatter({this.decimalRange})
: assert(decimalRange == null || decimalRange > 0);
final int decimalRange;
@override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue, // unused.
TextEditingValue newValue,
) {
TextSelection newSelection = newValue.selection;
String truncated = newValue.text;
if (decimalRange != null) {
String value = newValue.text;
if (value.contains(".") &&
value.substring(value.indexOf(".") + 1).length > decimalRange) {
truncated = oldValue.text;
newSelection = oldValue.selection;
} else if (value == ".") {
truncated = "0.";
newSelection = newValue.selection.copyWith(
baseOffset: math.min(truncated.length, truncated.length + 1),
extentOffset: math.min(truncated.length, truncated.length + 1),
);
}
return TextEditingValue(
text: truncated,
selection: newSelection,
composing: TextRange.empty,
);
}
return newValue;
}
}
6 Comments
, as decimal separator, like in SpanishHere is a solution which works for me
TextFormField(
inputFormatters: [
WhitelistingTextInputFormatter(RegExp(r'^\d+\.?\d{0,2}')),
],
)
If you want to allow input like (.21) or (.25)
Here is a solution-
TextFormField(
inputFormatters: [
WhitelistingTextInputFormatter(RegExp(r'^(\d+)?\.?\d{0,2}')),
],
)
5 Comments
WhitelistingTextInputFormatter is deprecated use FilteringTextInputFormatter.allow(RegExp(r'^\d+\.?\d{0,2}')) instead.import 'package:flutter/services.dart';WhitelistingTextInputFormatter and BlacklistingTextInputFormatter into FilteringTextInputFormatter that @joe_inz mentions, stating in the answer for which Flutter versions you should use each. It doesn't look to me like any functionality changed - rather it appears the language change was for woke/BLM reasons following George Floyd's death.after Flutter Version v1.20.0-1.0. use
TextFormField(
keyboardType: TextInputType.numberWithOptions(decimal: true),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'^\d+\.?\d{0,2}')),
],
),
1 Comment
For Dart 2.00+
TextFormField(
keyboardType: TextInputType.numberWithOptions(decimal: true),
inputFormatters: [
// Allow Decimal Number With Precision of 2 Only
FilteringTextInputFormatter.allow(RegExp(r'^\d*\.?\d{0,2}')),
],
It allows decimals like 1., .89, 8.99
4 Comments
TextInputFormatter.withFunction( (oldValue, newValue) => newValue.copyWith(text: newValue.text.replaceAll(',', '.'), ),)A shorter Version of DecimalTextInputFormatter using Regexp:
class DecimalTextInputFormatter extends TextInputFormatter {
DecimalTextInputFormatter({int decimalRange, bool activatedNegativeValues})
: assert(decimalRange == null || decimalRange >= 0,
'DecimalTextInputFormatter declaretion error') {
String dp = (decimalRange != null && decimalRange > 0) ? "([.][0-9]{0,$decimalRange}){0,1}" : "";
String num = "[0-9]*$dp";
if(activatedNegativeValues) {
_exp = new RegExp("^((((-){0,1})|((-){0,1}[0-9]$num))){0,1}\$");
}
else {
_exp = new RegExp("^($num){0,1}\$");
}
}
RegExp _exp;
@override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue,
TextEditingValue newValue,
) {
if(_exp.hasMatch(newValue.text)){
return newValue;
}
return oldValue;
}
}
2 Comments
Dart SDK version: 2.13.4 (stable) Flutter 2.2.3 • channel stable
i'm writing this answer on July 25, 2021, suggesting a little bit simpler solution, only using built-in TextField's inputFormatters.
i'm trying to ensure all of you, that the field won't accept floating point longer than 2(accepted: 12.25 vs notAccepted: 65.536). And also, it won't accept multiple dots, only accept a single dot(accepted: 12.25 vs notAccepted: 1.1.11, 1.11, .1.1, 1.1.1.1, whatsoever..).
The difference considering the other answers is that the code below won't accept .1 which is equal to 0.1 programmatically, which is actually way more user-friendly. And it is simple, nice to look at for us. You can just copy and paste the code below into inputFormatters: [].
If you want to accept both 0.1 and .1(not only 0.1), you can just comment out FilteringTextInputFormatter.allow(RegExp(r'^\d+\.?\d*'))!
inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r'^(\d+)?\.?\d{0,2}')), FilteringTextInputFormatter.allow(RegExp(r'^\d+\.?\d*')), ]
When you want to change the maximum decimal point, you can change the N value in the line below:
inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r'^(\d+)?\.?\d{0,N}')), FilteringTextInputFormatter.allow(RegExp(r'^\d+\.?\d*')), ]
First example shows the case in which you want to limit decimal point to 2, and the N value exactly controls the limit. You might try within your own code [:
Appreciate all the other answers, hope this answer might help future wanderers! Have a wonderful day [:
Comments
If you are looking for a regexp to handle comma and dot with 2 decimals try this version:
TextFormField(
keyboardType: const TextInputType.numberWithOptions(decimal: true),
decoration: textFieldDecoration("Price with only 2 decimals and handling comma"),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'(^\d*[\.\,]?\d{0,2})')),
],
);
1 Comment
RegExp(r'(^\d*[.,]?\d{0,2})') instead of RegExp(r'(^\d*[\.\,]?\d{0,2})')Maybe a little late for you, but I also improved a little:
- Allow only 1
. - Allow negative
- Place negative sign on beginning
Hope it helps ;)
import 'package:flutter/services.dart';
class NumberTextInputFormatter extends TextInputFormatter {
NumberTextInputFormatter({this.decimalRange}) : assert(decimalRange == null || decimalRange > 0);
final int decimalRange;
@override
TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
TextEditingValue _newValue = this.sanitize(newValue);
String text = _newValue.text;
if (decimalRange == null) {
return _newValue;
}
if (text == '.') {
return TextEditingValue(
text: '0.',
selection: _newValue.selection.copyWith(baseOffset: 2, extentOffset: 2),
composing: TextRange.empty,
);
}
return this.isValid(text) ? _newValue : oldValue;
}
bool isValid(String text) {
int dots = '.'.allMatches(text).length;
if (dots == 0) {
return true;
}
if (dots > 1) {
return false;
}
return text.substring(text.indexOf('.') + 1).length <= decimalRange;
}
TextEditingValue sanitize(TextEditingValue value) {
if (false == value.text.contains('-')) {
return value;
}
String text = '-' + value.text.replaceAll('-', '');
return TextEditingValue(text: text, selection: value.selection, composing: TextRange.empty);
}
}
and (don't forget to import the previous class)
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class NumberFormField extends StatelessWidget {
final InputDecoration decoration;
final TextEditingController controller;
final int decimalRange;
const NumberFormField({Key key, this.decoration, this.controller, this.decimalRange}) :super(key: key);
@override
Widget build(BuildContext context) {
return TextFormField(
decoration: this.decoration,
controller: this.controller,
keyboardType: TextInputType.numberWithOptions(decimal: true),
inputFormatters: [
WhitelistingTextInputFormatter(RegExp(r'[\d+\-\.]')),
NumberTextInputFormatter(decimalRange: this.decimalRange),
],
);
}
}
Comments
I extended the functionalities ... I hope you can find it useful. Tell me if you can improve even more please.
import 'package:flutter/services.dart';
import 'dart:math' as math;
class DecimalTextInputFormatter extends TextInputFormatter {
DecimalTextInputFormatter({this.decimalRange, this.activatedNegativeValues})
: assert(decimalRange == null || decimalRange >= 0,
'DecimalTextInputFormatter declaretion error');
final int decimalRange;
final bool activatedNegativeValues;
@override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue, // unused.
TextEditingValue newValue,
) {
TextSelection newSelection = newValue.selection;
String truncated = newValue.text;
if (newValue.text.contains(' ')) {
return oldValue;
}
if (newValue.text.isEmpty) {
return newValue;
} else if (double.tryParse(newValue.text) == null &&
!(newValue.text.length == 1 &&
(activatedNegativeValues == true ||
activatedNegativeValues == null) &&
newValue.text == '-')) {
return oldValue;
}
if (activatedNegativeValues == false &&
double.tryParse(newValue.text) < 0) {
return oldValue;
}
if (decimalRange != null) {
String value = newValue.text;
if (decimalRange == 0 && value.contains(".")) {
truncated = oldValue.text;
newSelection = oldValue.selection;
}
if (value.contains(".") &&
value.substring(value.indexOf(".") + 1).length > decimalRange) {
truncated = oldValue.text;
newSelection = oldValue.selection;
} else if (value == ".") {
truncated = "0.";
newSelection = newValue.selection.copyWith(
baseOffset: math.min(truncated.length, truncated.length + 1),
extentOffset: math.min(truncated.length, truncated.length + 1),
);
}
return TextEditingValue(
text: truncated,
selection: newSelection,
composing: TextRange.empty,
);
}
return newValue;
}
}
2 Comments
The answer by @AjayKumar allows to limit text input to required decimal places.But my requirement was to avoid another character from keyboard except the number and a dot.So, I updated @AjayKumar's above answer
import 'package:flutter/services.dart';
import 'dart:math' as math;
class DecimalTextInputFormatter extends TextInputFormatter {
DecimalTextInputFormatter({this.decimalRange})
: assert(decimalRange == null || decimalRange > 0);
final int decimalRange;
@override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue, // unused.
TextEditingValue newValue,
) {
TextSelection newSelection = newValue.selection;
String truncated = newValue.text;
if (decimalRange != null) {
String value = newValue.text;
if (value.contains(',') ||
value.contains('-') ||
value.contains(' ') ||
value.contains('..')) {
truncated = oldValue.text;
newSelection = oldValue.selection;
} else if (value.contains(".") &&
value.substring(value.indexOf(".") + 1).length > decimalRange) {
truncated = oldValue.text;
newSelection = oldValue.selection;
} else if (value == ".") {
truncated = "0.";
newSelection = newValue.selection.copyWith(
baseOffset: math.min(truncated.length, truncated.length + 1),
extentOffset: math.min(truncated.length, truncated.length + 1),
);
}
return TextEditingValue(
text: truncated,
selection: newSelection,
composing: TextRange.empty,
);
}
return newValue;
} }
Comments
And avoiding non necessary zeros... Please debug this code.
import 'dart:math' as math;
import 'package:flutter/services.dart';
class DecimalTextInputFormatter extends TextInputFormatter {
DecimalTextInputFormatter({this.decimalRange, this.activatedNegativeValues})
: assert(decimalRange == null || decimalRange >= 0,
'DecimalTextInputFormatter declaretion error');
final int decimalRange;
final bool activatedNegativeValues;
@override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue, // unused.
TextEditingValue newValue,
) {
TextSelection newSelection = newValue.selection;
String truncated = newValue.text;
if (newValue.text.contains(' ')) {
return oldValue;
}
if (newValue.text.isEmpty) {
return newValue;
} else if (double.tryParse(newValue.text) == null &&
!(newValue.text.length == 1 &&
(activatedNegativeValues == true ||
activatedNegativeValues == null) &&
newValue.text == '-')) {
return oldValue;
}
if (activatedNegativeValues == false &&
double.tryParse(newValue.text) < 0) {
return oldValue;
}
if ((double.tryParse(oldValue.text) == 0 && !newValue.text.contains('.'))) {
if (newValue.text.length >= oldValue.text.length) {
return oldValue;
}
}
if (decimalRange != null) {
String value = newValue.text;
if (decimalRange == 0 && value.contains(".")) {
truncated = oldValue.text;
newSelection = oldValue.selection;
}
if (value.contains(".") &&
value.substring(value.indexOf(".") + 1).length > decimalRange) {
truncated = oldValue.text;
newSelection = oldValue.selection;
} else if (value == ".") {
truncated = "0.";
newSelection = newValue.selection.copyWith(
baseOffset: math.min(truncated.length, truncated.length + 1),
extentOffset: math.min(truncated.length, truncated.length + 1),
);
}
return TextEditingValue(
text: truncated,
selection: newSelection,
composing: TextRange.empty,
);
}
return newValue;
}
}
Comments
For TextFeild in Flutter with Before decimal & After decimal length validation class.
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'dart:math' as math;
class DecimalTextInputFormatter extends TextInputFormatter {
DecimalTextInputFormatter({this.decimalRange,this.beforeDecimalRange})
: assert(decimalRange == null || decimalRange > 0 || beforeDecimalRange == null || beforeDecimalRange > 0 );
final int decimalRange;
final int beforeDecimalRange;
@override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue, // unused.
TextEditingValue newValue,
) {
TextSelection newSelection = newValue.selection;
String truncated = newValue.text;
String value;
if(beforeDecimalRange != null){
value = newValue.text;
if(value.contains(".")){
if(value.split(".")[0].length > beforeDecimalRange){
truncated = oldValue.text;
newSelection = oldValue.selection;
}
}else{
if(value.length > beforeDecimalRange){
truncated = oldValue.text;
newSelection = oldValue.selection;
}
}
}
if (decimalRange != null) {
value = newValue.text;
if (value.contains(".") &&
value.substring(value.indexOf(".") + 1).length > decimalRange) {
truncated = oldValue.text;
newSelection = oldValue.selection;
} else if (value == ".") {
truncated = "0.";
newSelection = newValue.selection.copyWith(
baseOffset: math.min(truncated.length, truncated.length + 1),
extentOffset: math.min(truncated.length, truncated.length + 1),
);
}
return TextEditingValue(
text: truncated,
selection: newSelection,
composing: TextRange.empty,
);
}
return newValue;
}
}
In TextFeild , Ex. Before decimal 9 digit & after Decimal 2 digit allowed code below.
inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r'^\d+\.?\d{0,2}')),
DecimalTextInputFormatter(decimalRange: 2, beforeDecimalRange: 9)
],
keyboardType: TextInputType.numberWithOptions(decimal: true),
Comments
This worked for me (Feb/2022)
Restricts the text to 2 decimal point and have only 1 '.' (period)
0 will be automatically added to the start of the number if user go and manually remove the digit before the '.'
PS: A Slight edit to the answer
TextFormField
TextFormField(
autofocus: false,
keyboardType: TextInputType.number,
controller: controller,
inputFormatters: [
DecimalTextInputFormatter(decimalRange: 2),
],
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please add amount.';
}
return null;
},
DecimalTextInputFormatter
import 'package:flutter/services.dart';
import 'dart:math' as math;
class DecimalTextInputFormatter extends TextInputFormatter {
DecimalTextInputFormatter({required this.decimalRange})
: assert(decimalRange > 0);
final int decimalRange;
@override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue,
TextEditingValue newValue,
) {
TextSelection newSelection = newValue.selection;
String truncated = newValue.text;
String value = newValue.text;
if (value.contains(".") &&
value.substring(value.indexOf(".") + 1).length > decimalRange) {
truncated = oldValue.text;
newSelection = oldValue.selection;
} else if (value == ".") {
truncated = "0.";
newSelection = newValue.selection.copyWith(
baseOffset: math.min(truncated.length, truncated.length + 1),
extentOffset: math.min(truncated.length, truncated.length + 1),
);
} else if (value.contains(".")) {
String tempValue = value.substring(value.indexOf(".") + 1);
if (tempValue.contains(".")) {
truncated = oldValue.text;
newSelection = oldValue.selection;
}
if (value.indexOf(".") == 0) {
truncated = "0" + truncated;
newSelection = newValue.selection.copyWith(
baseOffset: math.min(truncated.length, truncated.length + 1),
extentOffset: math.min(truncated.length, truncated.length + 1),
);
}
}
if (value.contains(" ") || value.contains("-")) {
truncated = oldValue.text;
newSelection = oldValue.selection;
}
return TextEditingValue(
text: truncated,
selection: newSelection,
composing: TextRange.empty,
);
}
}
Comments
I think this is the most simplest and only way working for me:
inputFormatters: [ LengthLimitingTextInputFormatter(2), ]
TextEditingControllerto listen for the inputs and manage your logic there.