'Flutter TextField with currency format

There's is some way to do a money format in a TextField to when the user going typing the value it going already formatting in real time?

formating while typing.

Like in the above image, while the user is typing the format goes updating the value formatted already.

[UPDATE]

I just found this library that makes it works like a charm: https://pub.dartlang.org/packages/flutter_masked_text



Solution 1:[1]

An easy solution to set a custom money mask, is to use the flutter_masked_text package:

1 - First of all, you need add this packege to your package's pubspec.yaml file:

dependencies:
  flutter_masked_text: ^0.7.0

2 - After that, install the package using the command line (as below), or use a graphic interface for it, if you are using the IntelliJ IDEA just click in the button "Packages get".

flutter packages get

3 - Now in your Dart code, import it...

import 'package:flutter_masked_text/flutter_masked_text.dart';

4 - Lastly, change your TextField controller code from "TextEditingController" to "MoneyMaskedTextController":

  //final lowPrice = TextEditingController(); //before
  final lowPrice = MoneyMaskedTextController(decimalSeparator: '.', thousandSeparator: ','); //after

Solution 2:[2]

[THIS CODE DOESN'T WORKS FOR ALL CASES]

I just got it working this way, sharing in case someone needs too:

TextField

TextFormField(  
    //validator: ,  
    controller: controllerValor,  
    inputFormatters: [  
        WhitelistingTextInputFormatter.digitsOnly,
        // Fit the validating format.
        //fazer o formater para dinheiro
        CurrencyInputFormatter()
    ],
    keyboardType: TextInputType.number, ...  

TextInputFormatter

class CurrencyInputFormatter extends TextInputFormatter {

    TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {

        if(newValue.selection.baseOffset == 0){
            print(true);
            return newValue;
        }

        double value = double.parse(newValue.text);

        final formatter = NumberFormat.simpleCurrency(locale: "pt_Br");

        String newText = formatter.format(value/100);

        return newValue.copyWith(
            text: newText,
            selection: new TextSelection.collapsed(offset: newText.length));
    }
}

This is the result of the code:

enter image description here

Solution 3:[3]

enter image description here


Use intl package. Full code:

import 'package:intl/intl.dart';

class _HomePageState extends State<HomePage> {
  final _controller = TextEditingController();
  static const _locale = 'en';
  String _formatNumber(String s) => NumberFormat.decimalPattern(_locale).format(int.parse(s));
  String get _currency => NumberFormat.compactSimpleCurrency(locale: _locale).currencySymbol;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: TextField(
        controller: _controller,
        decoration: InputDecoration(prefixText: _currency),
        keyboardType: TextInputType.number,
        onChanged: (string) {
          string = '${_formatNumber(string.replaceAll(',', ''))}';
          _controller.value = TextEditingValue(
            text: string,
            selection: TextSelection.collapsed(offset: string.length),
          );
        },
      ),
    );
  }
}

Solution 4:[4]

This library works perfect for me:

https://pub.dev/packages/currency_text_input_formatter

...
inputFormatters: [
  CurrencyTextInputFormatter(
    decimalDigits: 0,
    locale: 'ru',
  )
]
...

Solution 5:[5]

Updated the code from @AndréLuis to limit the number of digits (maxDigits), thanks for sharing.

import 'package:flutter/services.dart';
import 'package:intl/intl.dart';

class CurrencyPtBrInputFormatter extends TextInputFormatter {
  CurrencyPtBrInputFormatter({this.maxDigits});
  final int maxDigits;

  TextEditingValue formatEditUpdate(
      TextEditingValue oldValue, TextEditingValue newValue) {

    if (newValue.selection.baseOffset == 0) {
      return newValue;
    }

    if (maxDigits != null && newValue.selection.baseOffset > maxDigits) {
      return oldValue;
    }

    double value = double.parse(newValue.text);
    final formatter = new NumberFormat("#,##0.00", "pt_BR");
    String newText = "R\$ " + formatter.format(value / 100);
    return newValue.copyWith(
        text: newText,
        selection: new TextSelection.collapsed(offset: newText.length));
  }
}

Use the code bellow for the TextFormField, I'm also parsing the value to double, removing the non-digit chars using RegExp.

TextFormField(
  maxLines: 1,
  keyboardType: TextInputType.number,
  inputFormatters: [
    WhitelistingTextInputFormatter.digitsOnly,
    CurrencyPtBrInputFormatter(maxDigits: 8),
  ],
  onSaved: (value) {
    String _onlyDigits = value.replaceAll(RegExp('[^0-9]'), "");
    double _doubleValue = double.parse(_onlyDigits) / 100;
    return _valor = _doubleValue;
  },
);

Solution 6:[6]

To make a cleaner code the umasked value could be included in the Formatter class as a method. So when the value got changed you will be able to call it and simplifying the code.

Widget build(BuildContext context) {
    var maskFormatter = new CurrencyPtBrFormatter(maxDigits: 12);
    return Scaffold(
        body: SingleChildScrollView(
            controller: _scrollController,
            child: Column(
              children: <Widget>[
                TextField(
                  keyboardType: TextInputType.number,
                  inputFormatters: [
                    WhitelistingTextInputFormatter.digitsOnly,
                    maskFormatter,
                  ],
                  controller: _yourController,
                  onChanged: (value) {
                    print(maskFormatter.getUnmaskedDouble()); // here the umasked value
                  },
                  onEditingComplete: () {
                    mudarFocoCampo(context, _estoqueFocus, _codigoFocus);
                  },
                )
              ],
            )));
  }

Here the complete formatter with umasked method.

import 'package:flutter/services.dart';
import 'package:intl/intl.dart';
class CurrencyPtBrFormatter extends TextInputFormatter {
  CurrencyPtBrFormatter({this.maxDigits});
  final int maxDigits;
  double _uMaskValue;
  TextEditingValue formatEditUpdate(
      TextEditingValue oldValue, TextEditingValue newValue) {
    if (newValue.selection.baseOffset == 0) {
      return newValue;
    }
    if (maxDigits != null && newValue.selection.baseOffset > maxDigits) {
      return oldValue;
    }
    double value = double.parse(newValue.text);
    final formatter = new NumberFormat("#,##0.00", "pt_BR");
    String newText = "R\$ " + formatter.format(value / 100);
    //setting the umasked value
    _uMaskValue = value / 100;
    return newValue.copyWith(
        text: newText,
        selection: new TextSelection.collapsed(offset: newText.length));
  }
  //here the method
  double getUnmaskedDouble() {
    return _uMaskValue;
  }
}

Solution 7:[7]

Using pattern_formatter package,

TextField(
  keyboardType: TextInputType.number,
  inputFormatters: [
    ThousandsFormatter()
  ],
)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 GPaiva
Solution 3
Solution 4 Ilya Iksent
Solution 5 daniloxvalle
Solution 6
Solution 7 Shlomi