flutter TextField限制输入为合法小数

描述

对于金额等的输入,常常要求TextField限制输入为小数,可使用以下约束:

   inputFormatters: [
            WhitelistingTextInputFormatter(RegExp("[0-9.]")), //只允许输入小数
          ],

但这种限制会有问题,比如可以输入0.1.1这种其实就不是小数了,并且不能限制小数点的输入位数。

限制输入为合法小数

继承TextInputFormatter类,重写formatEditUpdate方法:

import 'package:flutter/services.dart';

class XNumberTextInputFormatter extends TextInputFormatter {
  int _maxIntegerLength;
  int _maxDecimalLength;
  bool _isAllowDecimal;

  /// [maxIntegerLength]限定整数的最大位数,为null时不限
  /// [maxDecimalLength]限定小数点的最大位数,为null时不限
  /// [isAllowDecimal]是否可以为小数,默认是可以为小数,也就是可以输入小数点
  XNumberTextInputFormatter(
      {int maxIntegerLength, int maxDecimalLength, bool isAllowDecimal = true})
      : _maxIntegerLength = maxIntegerLength,
        _maxDecimalLength = maxDecimalLength,
        _isAllowDecimal = isAllowDecimal;

  @override
  TextEditingValue formatEditUpdate(
      TextEditingValue oldValue, TextEditingValue newValue) {
    String value = newValue.text?.trim(); //去掉前后空格
    int selectionIndex = newValue.selection.end;
    if (_isAllowDecimal) {
      if (value == '.') {
        value = '0.';
        selectionIndex++;
      } else if (value != '' && _isToDoubleError(value)) {
        //不是double输入数据
        return _oldTextEditingValue(oldValue);
      }
      //包含小数点
      if (value.contains('.')) {
        int pointIndex = value.indexOf('.');
        String beforePoint = value.substring(0, pointIndex);
//      print('$beforePoint');
        String afterPoint = value.substring(pointIndex + 1, value.length);
//      print('$afterPoint');
        //小数点前面没内容补0
        if (beforePoint.length == 0) {
          value = '0.${afterPoint ?? ''}';
          selectionIndex++;
        } else {
          //限定整数位数
          if (null != _maxIntegerLength) {
            if (beforePoint.length > _maxIntegerLength) {
              return _oldTextEditingValue(oldValue);
            }
          }
        }
        //限定小数点位数
        if (null != _maxDecimalLength) {
          if (afterPoint.length > _maxDecimalLength) {
            return _oldTextEditingValue(oldValue);
          }
        }
      } else {
        //限定整数位数
        if (null != _maxIntegerLength) {
          if (value.length > _maxIntegerLength) {
            return _oldTextEditingValue(oldValue);
          }
        }
      }
    } else {
      if (value.contains('.') ||
          (value != '' && _isToDoubleError(value)) ||
          (null!=_maxIntegerLength&&value.length > _maxIntegerLength)) {
        return _oldTextEditingValue(oldValue);
      }
    }

    return TextEditingValue(
      text: value,
      selection: TextSelection.collapsed(offset: selectionIndex),
    );
  }

  ///返回旧的输入内容
  TextEditingValue _oldTextEditingValue(TextEditingValue oldValue) {
    return TextEditingValue(
      text: oldValue.text,
      selection: TextSelection.collapsed(offset: oldValue.selection.end),
    );
  }

  ///输入内容不能解析成double
  bool _isToDoubleError(String value) {
    try {
      double.parse(value);
    } catch (e) {
      return true;
    }
    return false;
  }
}

示例

         TextField(
              //设置键盘可录入为小数
              keyboardType: TextInputType.numberWithOptions(decimal: true),

              inputFormatters: [
                XNumberTextInputFormatter(
                    maxIntegerLength: null, maxDecimalLength: 2,isAllowDecimal: true),
              ],
              onChanged: (value) {
                print(value);
                print(double.tryParse(value));
              },
            ),

温馨提示:

  • keyboardType: TextInputType.numberWithOptions(decimal: true) 控制弹出键盘为带小数点的数字键盘,不是必须的,为了体验更好;
  • inputFormatters:对输入要显示在输入框的内容进行处理;

效果

效果.gif

demo传送门

你可能感兴趣的:(flutter TextField限制输入为合法小数)