regexflutterdartinputformatter

inputFormatter should allow just decimal numbers and negative numbers


I want to allow users to just adding numbers "12345" and decimal numbers like "21321.12312" and negative numbers like -23423.32432. Users shouldn't be able to add multiple "." like "12..32" and add "-" just in first of input like -324.34 not like 324-4323. I used this regEx r'^(-?\d+\.\d+)(\s*,\s*-?\d+\.\d+)+$' but can't enter anything.

TextField code:

TextFormField(
          inputFormatters: [
            FilteringTextInputFormatter.allow(
                RegExp(r'^(-?\d+\.\d+)(\s*,\s*-?\d+\.\d+)+$')),
          ],
          controller: budget,
          keyboardType: TextInputType.number,
          decoration: InputDecoration(
            contentPadding:
                EdgeInsets.only(right: 20, left: 20, top: 10, bottom: 10),
            hintText: getTranslated(context, "budget_example"),
            hintStyle: TextStyle(fontSize: 13, fontFamily: "tahoma"),
            border: OutlineInputBorder(
              borderSide: BorderSide(width: 1, color: MyColors.secondary),
              borderRadius: BorderRadius.circular(100),
            ),
          ),
        ),

Solution

  • Allow only 1 .

    Allow negative

    Place negative sign on beginning

    We should create our own input formatter

    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),
          ],
        );
      }
    }