Jaya kumar
Jaya kumar

Reputation: 99

How to restrict two dots in flutter?

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

Answers (6)

Ben Roberts
Ben Roberts

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

Vishal Zaveri
Vishal Zaveri

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

om-ha
om-ha

Reputation: 3602

Flutter 1.20 update

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+)?")),
    ],
);

Solution

Here is what you need to do for your specific use case:

TextFormField(
    inputFormatters: [
        WhitelistingTextInputFormatter(RegExp(r"\d+([\.]\d+)?")),
    ],
);

Explanation

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.

Regex Dissection

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.

Sources

Upvotes: 5

Mathulan
Mathulan

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

Zah
Zah

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

Crazy Lazy Cat
Crazy Lazy Cat

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

Related Questions