Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/flutter/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Flutter 仅允许输入3位十进制数字_Flutter - Fatal编程技术网

Flutter 仅允许输入3位十进制数字

Flutter 仅允许输入3位十进制数字,flutter,Flutter,我想强制用户只输入一个点和3个小数点 我发现代码如下: class NumberRemoveExtraDotFormatter extends TextInputFormatter { NumberRemoveExtraDotFormatter({this.decimalRange = 3}) : assert(decimalRange == null || decimalRange > 0); final int decimalRange; @override Tex

我想强制用户只输入一个点和3个小数点

我发现代码如下:

class NumberRemoveExtraDotFormatter extends TextInputFormatter {
  NumberRemoveExtraDotFormatter({this.decimalRange = 3}) : assert(decimalRange == null || decimalRange > 0);

  final int decimalRange;

  @override
  TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
    var nValue = newValue.text;
    var nSelection = newValue.selection;

    Pattern p = RegExp(r'(\d+\.?)|(\.?\d+)|(\.?)');
    nValue = p.allMatches(nValue).map<String>((Match match) => match.group(0)).join();

    if (nValue.startsWith('.')) {
      nValue = '0.';
    } else if (nValue.contains('.')) {
      if (nValue.substring(nValue.indexOf('.') + 1).length > decimalRange) {
        nValue = oldValue.text;
      } else {
        if (nValue.split('.').length > 2) {
          var split = nValue.split('.');
          nValue = split[0] + '.' + split[1];
        }
      }
    }

    nSelection = newValue.selection.copyWith(
      baseOffset: math.min(nValue.length, nValue.length + 1),
      extentOffset: math.min(nValue.length, nValue.length + 1),
    );

    return TextEditingValue(text: Utils.addCommad(nValue), selection: nSelection, composing: TextRange.empty);
  }
}
class NumberRemoveExtraDotFormatter扩展了TextInputFormatter{
NumberRemoveExtraDotFormatter({this.decimalRange=3}):断言(decimalRange==null | | decimalRange>0);
最终整数小数范围;
@凌驾
TextEditingValue formatEditUpdate(TextEditingValue旧值,TextEditingValue新值){
var nValue=newValue.text;
var nSelection=newValue.selection;
模式p=RegExp(r'(\d+\.?)|(\.?\d+)|(\.?));
nValue=p.allMatches(nValue).map((Match-Match)=>Match.group(0)).join();
if(nValue.startsWith('.')){
nValue='0';
}else if(nValue.contains('.')){
if(nValue.substring(nValue.indexOf('.')+1.length>decimalRange){
nValue=oldValue.text;
}否则{
如果(nValue.split('.')。长度>2){
var split=n值分割('.');
nValue=split[0]+'.+split[1];
}
}
}
nSelection=newValue.selection.copyWith(
baseOffset:math.min(nValue.length,nValue.length+1),
extendtoffset:math.min(nValue.length,nValue.length+1),
);
返回TextEditingValue(文本:Utils.addCommad(nValue),选择:nSelection,组合:TextRange.empty);
}
}
但问题是,当用户输入超过3个小数点,然后想要删除时,它不会。因为数字保存在textformfield中,它们需要删除,直到它们达到3个小数点,而且当从输入光标的中间键入时,它们也会跳到末尾

另外,若用户输入的小数点超过3,我想将数字从右边移出

如何实现这一点?

尝试使用以下方法:

filteringtExputFormatter(RegExp(r'(^[0-9]*(?:\[0-9]{0,3})))),allow:true),


基本上,正则表达式将尝试匹配0个或更多出现的数字,后跟可选的十进制数,后跟十进制数后最多3个数字。您可以将其修改为同时使用负值
^(?:\-)?[0-9]*(?:\.[0-9]{0,3})$

如果您只想强制用户只输入一个点和三个小数点,这可能会起作用

FilteringTextInputFormatter.allow(RegExp(r'^\d+\.?\d{0,3}'))
根据你的评论:

  • 如何添加分隔符
  • 把号码移出去不起作用。当小数点达到最大值时,若用户开始键入小数部分,我想将数字移出。e、 g.当前值为0.333,用户设置光标位于第二个3(0.3 | 33)和类型2。那么该值必须为0.323
  • 我们可以使用来设置数字的格式

    这是我的代码,我没有进行彻底和详细的测试。如果您发现任何错误,请指出它们

    更新
    当输入最大分数位数为0的长数字时,将添加错误的数字。=>这并不取决于最大分数位数。它总是发生

    我认为NumberFormat中有一些意外的行为,我将其更改为custom方法,现在它支持负数

    class NumberInputFormatter extends TextInputFormatter {
      final int maximumFractionDigits;
    
      NumberInputFormatter({
        this.maximumFractionDigits = 3,
      }) : assert(maximumFractionDigits != null && maximumFractionDigits >= 0);
    
      @override
      TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
        var newText = newValue.text;
        var selectionOffset = newValue.selection.extent.offset;
        bool isNegative = false;
        if (newText.startsWith('-')) {
          newText = newText.substring(1);
          isNegative = true;
        }
        if (newText.isEmpty) {
          return newValue;
        }
        if (newText.indexOf('.') != newText.lastIndexOf('.')) {
          // inputted more than one dot.
          return oldValue;
        }
        if (newText.startsWith('.') && maximumFractionDigits > 0) {
          newText = '0$newText';
          selectionOffset += 1;
        }
        while (newText.length > 1 && !newText.startsWith('0.') && newText.startsWith('0')) {
          newText = newText.substring(1);
          selectionOffset -= 1;
        }
        if (_decimalDigitsOf(newText) > maximumFractionDigits) {
          // delete the extra digits.
          newText = newText.substring(0, newText.indexOf('.') + 1 + maximumFractionDigits);
        }
        if (newValue.text.length == oldValue.text.length - 1 &&
            oldValue.text.substring(newValue.selection.extentOffset, newValue.selection.extentOffset + 1) == ',') {
          // in this case, user deleted the thousands separator, we should delete the digit number before the cursor.
          newText = newText.replaceRange(newValue.selection.extentOffset - 1, newValue.selection.extentOffset, '');
          selectionOffset -= 1;
        }
        if (newText.endsWith('.')) {
          // in order to calculate the selection offset correctly, we delete the last decimal point first.
          newText = newText.replaceRange(newText.length - 1, newText.length, '');
        }
        int lengthBeforeFormat = newText.length;
        newText = _removeComma(newText);
        if (double.tryParse(newText) == null) {
          // invalid decimal number
          return oldValue;
        }
        newText = _addComma(newText);
        selectionOffset += newText.length - lengthBeforeFormat; // thousands separator newly added
        if (maximumFractionDigits > 0 && newValue.text.endsWith('.')) {
          // decimal point is at the last digit, we need to append it back.
          newText = '$newText.';
        }
        if (isNegative) {
          newText = '-$newText';
        }
        return TextEditingValue(
          text: newText,
          selection: TextSelection.collapsed(offset: min(selectionOffset, newText.length)),
        );
      }
    
      static int _decimalDigitsOf(String text) {
        var index = text?.indexOf('.') ?? -1;
        return index == -1 ? 0 : text.length - index - 1;
      }
    
      static String _addComma(String text) {
        StringBuffer sb = StringBuffer();
        var pointIndex = text.indexOf('.');
        String integerPart;
        String decimalPart;
        if (pointIndex >= 0) {
          integerPart = text.substring(0, pointIndex);
          decimalPart = text.substring(pointIndex);
        } else {
          integerPart = text;
          decimalPart = '';
        }
        List<String> parts = [];
        while (integerPart.length > 3) {
          parts.add(integerPart.substring(integerPart.length - 3));
          integerPart = integerPart.substring(0, integerPart.length - 3);
        }
        parts.add(integerPart);
        sb.writeAll(parts.reversed, ',');
        sb.write(decimalPart);
        return sb.toString();
      }
    
      static String _removeComma(String text) {
        return text.replaceAll(',', '');
      }
    }
    
    class NumberInputFormatter扩展了TextInputFormatter{
    最终整数最大分数位数;
    数字输入格式化程序({
    此.maximumFractionDigits=3,
    }):assert(maximumFractionDigits!=null&&maximumFractionDigits>=0);
    @凌驾
    TextEditingValue formatEditUpdate(TextEditingValue旧值,TextEditingValue新值){
    var newText=newValue.text;
    var selectionOffset=newValue.selection.extent.offset;
    bool为阴性=假;
    if(newText.startsWith('-')){
    newText=newText.substring(1);
    isNegative=true;
    }
    if(newText.isEmpty){
    返回新值;
    }
    if(newText.indexOf('.')!=newText.lastIndexOf('.')){
    //输入多个点。
    返回旧值;
    }
    if(newText.startsWith('.')&&maximumFractionDigits>0){
    newText='0$newText';
    selectionOffset+=1;
    }
    而(newText.length>1&&!newText.startsWith('0')&&newText.startsWith('0')){
    newText=newText.substring(1);
    selectionOffset-=1;
    }
    if(_decimaldigitof(newText)>maximumFractionDigits){
    //删除多余的数字。
    newText=newText.substring(0,newText.indexOf('.')+1+最大分数位数);
    }
    如果(newValue.text.length==oldValue.text.length-1&&
    oldValue.text.substring(newValue.selection.extendtoffset,newValue.selection.extendtoffset+1)=','){
    //在这种情况下,用户删除了千位分隔符,我们应该删除光标前的数字。
    newText=newText.replaceRange(newValue.selection.extendtoffset-1,newValue.selection.extendtoffset“”);
    selectionOffset-=1;
    }
    if(newText.endsWith('.')){
    //为了正确计算选择偏移量,我们首先删除最后一个小数点。
    newText=newText.replaceRange(newText.length-1,newText.length“”);
    }
    int lengthBeforeFormat=newText.length;
    新文本=_removeComma(新文本);
    if(double.tryParse(newText)==null){
    //无效的十进制数
    返回旧值;
    }
    新文本=_addComma(新文本);
    selectionOffset+=newText.length-lengthBeforeFormat;//新添加的千位分隔符
    if(maximumFractionDigits>0&&newValue.text.endsWith('.')){
    //小数点在最后一位,我们需要把它加回去。
    newText=“$newText”;
    }
    如果(为负){
    newText='-$newText';
    }
    返回TextEditingValue(
    文本:新文本,
    选择:TextSelection.Closed(偏移量:min(selectionOffset,newText.length)),
    );
    }
    静态整数小数位数(字符串文本){
    变量索引=文本?.indexOf('.')??-1;
    返回索引==-1?0:text.length-index-1;
    }
    静态字符串\u add逗号(字符串文本){
    StringBuffer sb=StringBuffer();
    var pointIndex=text.indexOf('.');
    字符串整数部分;
    弦分母;
    如果(点索引>=0){
    integerPart=text.substring(0,pointIndex);
    decimalPart=text.substring(pointIndex);
    }否则{
    inte
    
    import 'package:flutter/material.dart';
    import 'package:flutter/services.dart';
    import 'dart:math' as math;
    
    class DecimalChecker extends TextInputFormatter {
      DecimalChecker({this.decimalRange = 3})
          : assert(decimalRange == null || decimalRange > 0);
    
      final int decimalRange;
    
      @override
      TextEditingValue formatEditUpdate(
          TextEditingValue oldValue, TextEditingValue newValue) {
        String valueTxt = newValue.text;
        TextSelection valueSet = newValue.selection;
        var newlength = newValue.text.length;
        var oldlength = oldValue.text.length;
        if (oldlength < newlength) {
          Pattern p = RegExp(r'(\d+\.?)|(\.?\d+)|(\.?)');
          valueTxt = p
              .allMatches(valueTxt)
              .map<String>((Match match) => match.group(0))
              .join();
          print("------>");
          if (valueTxt.startsWith('.')) {
            valueTxt = '0.';
          } else if (valueTxt.contains('.')) {
            if (valueTxt.substring(valueTxt.indexOf('.') + 1).length >
                decimalRange) {
              valueTxt = oldValue.text;
            } else {
              if (valueTxt.split('.').length > 2) {
                List<String> split = valueTxt.split('.');
                valueTxt = split[0] + '.' + split[1];
              }
            }
          }
    
          valueSet = newValue.selection.copyWith(
            baseOffset: math.min(valueTxt.length, valueTxt.length + 1),
            extentOffset: math.min(valueTxt.length, valueTxt.length + 1),
          );
    
          return TextEditingValue(
              text: valueTxt, selection: valueSet, composing: TextRange.empty);
        } else {
          return TextEditingValue(
              text: valueTxt, selection: valueSet, composing: TextRange.empty);
        }
      }
    }
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter App',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: MyHomePage(title: 'My Decimal Check App'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);
    
      final String title;
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      TextEditingController numberController = TextEditingController();
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Padding(
                  padding: EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 0.0),
                  child: TextField(
                    controller: numberController,
                    keyboardType: TextInputType.numberWithOptions(decimal: true),
                    inputFormatters: [DecimalChecker()],
                    decoration: InputDecoration(
                      hintText: "Please enter Number",
                    ),
                  ),
                ),
              ],
            ),
          ),
        );
      }
    }