iOS中TextField只能输入数字且小数点后最多输入两位

本文介绍了一个UITextField的代理方法,用于监听并限制输入的内容。具体限制包括:只允许输入数字和一个小数点;小数点后最多两位;首位为0时必须跟小数点;提示输入错误。

在简书上看到保存下来的

/**
 *  textField的代理方法,监听textField的文字改变
 *  textField.text是当前输入字符之前的textField中的text
 *
 *  @param textField textField
 *  @param range     当前光标的位置
 *  @param string    当前输入的字符
 *
 *  @return 是否允许改变
 */
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    /*
     * 不能输入.0-9以外的字符。
     * 设置输入框输入的内容格式
     * 只能有一个小数点
     * 小数点后最多能输入两位
     * 如果第一位是.则前面加上0.
     * 如果第一位是0则后面必须输入点,否则不能输入。
     */

    // 判断是否有小数点
    if ([textField.text containsString:@"."]) {
        self.isHaveDian = YES;
    }else{
        self.isHaveDian = NO;
    }

    if (string.length > 0) {

        //当前输入的字符
        unichar single = [string characterAtIndex:0];
        BXLog(@"single = %c",single);

        // 不能输入.0-9以外的字符
        if (!((single >= '0' && single <= '9') || single == '.'))
        {
            [MBProgressHUD bwm_showTitle:@"您的输入格式不正确" toView:self hideAfter:1.0];
            return NO;
        }

        // 只能有一个小数点
        if (self.isHaveDian && single == '.') {
            [MBProgressHUD bwm_showTitle:@"最多只能输入一个小数点" toView:self hideAfter:1.0];
            return NO;
        }

        // 如果第一位是.则前面加上0.
        if ((textField.text.length == 0) && (single == '.')) {
            textField.text = @"0";
        }

        // 如果第一位是0则后面必须输入点,否则不能输入。
        if ([textField.text hasPrefix:@"0"]) {
            if (textField.text.length > 1) {
                NSString *secondStr = [textField.text substringWithRange:NSMakeRange(1, 1)];
                if (![secondStr isEqualToString:@"."]) {
                    [MBProgressHUD bwm_showTitle:@"第二个字符需要是小数点" toView:self hideAfter:1.0];
                    return NO;
                }
            }else{
                if (![string isEqualToString:@"."]) {
                    [MBProgressHUD bwm_showTitle:@"第二个字符需要是小数点" toView:self hideAfter:1.0];
                    return NO;
                }
            }
        }

        // 小数点后最多能输入两位
        if (self.isHaveDian) {
            NSRange ran = [textField.text rangeOfString:@"."];
            // 由于range.location是NSUInteger类型的,所以这里不能通过(range.location - ran.location)>2来判断
            if (range.location > ran.location) {
                if ([textField.text pathExtension].length > 1) {
                    [MBProgressHUD bwm_showTitle:@"小数点后最多有两位小数" toView:self hideAfter:1.0];
                    return NO;
                }
            }
        }

    }

    return YES;
}

作者:袁俊亮技术博客
链接:作者的简书链接
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

<think>首先,用户的问题是关于在Flutter中实现输入框限制只能输入数字小数点最多两位的方法。用户提供了几个引用,我需要参考这些引用来回答问题。 回顾用户提供的引用: - 引用[1]: 提到了使用TextInputFormatter.withFunction来处理小数点两位,并确保首位不为0。它使用了RegExp("[1-9]{1}[0-9.]*"),但建议改为RegExp(r'[1-9]{1}[0-9.]*')。 - 引用[2]: 简单地使用FilteringTextInputFormatter.allow(RegExp("[0-9.]"))来允许数字小数点,但没有处理小数点后位数或首位0的问题。 - 引用[3]: 列出了TextField的各种属性,但没有具体针对这个问题的解决方案。 - 引用[4]: 提到了使用正则和输入监听来限制输入为零或非零开头的最多两位小数数字,并提到了一个函数封装。 用户明确说:“上述引用仅供参考,并不是用户真正的需求”,但我应该参考它们来构建答案。用户的问题是:“我想查找在Flutter中实现输入框限制只能输入数字小数点最多两位的方法 请问Flutter实现输入框只能输入数字小数点最多两位的方法”。所以,我需要提供一个清晰的解决方案。 关键点: - 只能输入数字(0-9)和小数点.)。 - 小数点最多两位。 - 最好处理首位不为0的情况(除非是0.),以避免像"012"这样的输入。 从引用中提取有效方法: - 引用[1]和[4]给出了更完整的方案: - 使用TextInputFormatter.withFunction或自定义TextInputFormatter。 - 正则表达式来过滤输入。 - 处理小数点重复和位数限制。 最佳实践: - 使用TextInputFormatter来限制输入。 - 自定义一个TextInputFormatter来处理小数点最多两位。 步骤: 1. 导入必要的包:import 'package:flutter/services.dart'; 2.TextField中使用inputFormatters。 3. 定义一个自定义的TextInputFormatter来处理限制。 具体实现: - 允许输入数字小数点。 - 确保小数点只出现一次(不能有两个小数点)。 - 确保小数点最多两位数字。 - 最好处理首位不为0的情况(除非是小数点的开头)。 从引用[4],它提到了一个函数:onlyInputNumberWithDecimalPointFormatter(),这应该是一个自定义的formatter。 我可以基于引用[1]和[4]构建一个自定义formatter: - 使用TextInputFormatter.withFunction。 - 在函数中,检查newValue: - 如果包含小数点,确保小数点后位数不超过2。 - 确保小数点只出现一次。 - 检查首位是否为0(如果整个输入不以小数点开头)。 正则表达式可能不足以处理所有情况,因为正则表达式的限制可能不完美。更可靠的方式是使用逻辑在TextInputFormatter中检查。 示例代码: - 定义一个TextInputFormatter的子类或使用withFunction。 - 在回调中,验证输入: - 检查是否有多个小数点:如果是,返回oldValue。 - 检查小数点后位数:如果有小数点,计算小数点后字符数不超过2。 - 检查开头是否为0:如果输入以0开头不是小数(如"012"),可能需要限制。 参考引用[1]: - newValue.text.indexOf(".") != newValue.text.lastIndexOf("."):检查小数点是否唯一。 - newValue.text.indexOf(".") > -1 && ((newValue.text.length - 1) - newValue.text.lastIndexOf(".")) > 2:检查小数点后位数是否超过2(长度减去索引减1)。 - 然后使用FilteringTextInputFormatter.allow(RegExp(r'[1-9]{1}[0-9.]*')):这允许首位是1-9,然后是数字小数点。但问题:如果输入"0.12",它可能被拒绝,因为以0开头。需要调整允许0开头的如果后面有小数点。 改进: - 正则表达式应该允许0开头如果是小数部分,比如允许"0.12"。引用[1]中RegExp(r'[1-9]{1}[0-9.]*')不允许0开头,这可能不是最优。所以,最好使用通用正则如RegExp(r'^\d*\.?\d{0,2}$'),但这可能不完美。 更健壮的方式: - 使用TextInputFormatter来动态检查,而不是纯正则。 - 定义一个自定义formatter类似引用[4]。 我将创建一个自定义TextInputFormatter类。 回答结构: - 清晰解释:先简要介绍方法。 - 提供代码示例:定义一个自定义TextInputFormatter。 - 解释关键点:如何处理小数点唯一性、位数限制、首位0问题。 - 集成到TextField:展示如何在TextField中使用。 - 确保中文回答。 - 生成相关问题。 代码示例: - 定义类: ```dart import 'package:flutter/services.dart'; class DecimalTextInputFormatter extends TextInputFormatter { @override TextEditingValue formatEditUpdate( TextEditingValue oldValue, TextEditingValue newValue) { // 处理逻辑 // 如果新值包含多个小数点,返回旧值 if (newValue.text.indexOf('.') != newValue.text.lastIndexOf('.')) { return oldValue; } // 如果包含小数点 if (newValue.text.contains('.') { // 找到小数点位置 int dotIndex = newValue.text.indexOf('.'); // 获取小数点后部分 String decimalPart = newValue.text.substring(dotIndex + 1); // 如果小数部分长度超过2,返回旧值 if (decimalPart.length > 2) { return oldValue; } } // 检查首位是否为0后面有数字(如"012"),不允许;但允许"0."或小数点后 if (newValue.text.startsWith('0') && newValue.text.length > 1 && !newValue.text.startsWith('0.')) { return oldValue; } // 允许数字小数点,但已经通过以上检查 // 额外确保输入只包含数字小数点 if (RegExp(r'^[0-9]*\.?[0-9]*$').hasMatch(newValue.text)) { return newValue; } return oldValue; } } ``` - 在TextField中使用: ```dart TextField( inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r'[0-9.]')), // 先允许数字小数点 DecimalTextInputFormatter(), // 应用自定义逻辑 ], keyboardType: TextInputType.numberWithOptions(decimal: true), // 数字键盘带小数点 ) ``` 改进点: - 先使用FilteringTextInputFormatter.allow(RegExp(r'[0-9.]'))来只允许数字小数点输入。 - 然后应用自定义formatter处理精细规则。 - 在自定义formatter中,处理小数点重复、小数位长度、首位0问题。 首位0问题: - 允许"0"或"0.12",但不允许"012"。 - 在formatEditUpdate中检查:if (newValue.text.startsWith('0') && newValue.text.length > 1 && !newValue.text.startsWith('0.')),则返回oldValue。 正则检查:使用RegExp(r'^[0-9]*\.?[0-9]*$')来确保只包含数字小数点,但前面的Filtering应该已经处理了,所以要确保。 集成多个formatters。 现在,构建回答: 1. 介绍需求和方法。 2. 提供自定义TextInputFormatter代码。 3. 展示如何在TextField中使用。 4. 解释关键逻辑。 5. 生成相关问题。 相关问题: - 如何限制输入框只能输入整数? - 如何处理更多的小数限制? - 如何自定义键盘类型? - 如何验证输入值? 确保回答真实可靠:基于Flutter文档和常见实践。 </think>### Flutter实现输入框限制只能输入数字小数点最多两位的方法 在Flutter中,要实现输入框只能输入数字(0-9)和小数点.),并限制小数点最多两位,可以使用`TextInputFormatter`结合自定义逻辑来处理。这种方法通过过滤输入、验证小数点唯一性和小数位长度来确保用户输入符合要求。下面我将逐步解释实现方法,并提供完整的代码示例。 #### 核心实现步骤 1. **导入必要包**:使用`package:flutter/services.dart`中的`TextInputFormatter`相关类。 2. **定义自定义TextInputFormatter**:创建一个类继承自`TextInputFormatter`,在`formatEditUpdate`方法中添加逻辑: - 检查小数点是否唯一(不能有多个小数点)。 - 限制小数点最多两位数字。 - 处理首位不为0的问题(允许"0."但禁止"012"等无效输入)。 3. **在TextField中使用**:将自定义formatter添加到`inputFormatters`列表中,并设置`keyboardType`为数字键盘。 4. **添加基础过滤**:先用`FilteringTextInputFormatter.allow(RegExp(r'[0-9.]'))`确保只允许数字小数点输入。 #### 完整代码示例 以下是实现该功能的Dart代码,包含自定义formatter和TextField集成: ```dart import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; // 自定义TextInputFormatter:限制只能输入数字小数点小数点最多两位 class DecimalTextInputFormatter extends TextInputFormatter { @override TextEditingValue formatEditUpdate( TextEditingValue oldValue, TextEditingValue newValue) { // 检查输入是否为空 if (newValue.text.isEmpty) { return newValue; } // 1. 禁止首位为0后面紧跟数字(如"012"),但允许"0."或"0.1" if (newValue.text.startsWith('0') && newValue.text.length > 1 && !newValue.text.startsWith('0.')) { return oldValue; // 返回旧值,阻止无效输入 } // 2. 检查是否有多个小数点(indexOf和lastIndexOf不一致表示有重复) if (newValue.text.indexOf('.') != newValue.text.lastIndexOf('.')) { return oldValue; // 返回旧值,阻止多个小数点 } // 3. 检查小数点后位数是否超过2位 final dotIndex = newValue.text.indexOf('.'); if (dotIndex != -1) { final decimalPart = newValue.text.substring(dotIndex + 1); if (decimalPart.length > 2) { return oldValue; // 返回旧值,阻止小数位超过2位 } } // 4. 确保输入只包含数字小数点(正则过滤) if (!RegExp(r'^[0-9]*\.?[0-9]*$').hasMatch(newValue.text)) { return oldValue; // 返回旧值,阻止非法字符 } return newValue; // 输入有效,返回新值 } } // 在TextFormField中使用示例 class NumberInputField extends StatelessWidget { @override Widget build(BuildContext context) { return TextFormField( keyboardType: TextInputType.numberWithOptions(decimal: true), // 数字键盘带小数点 inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r'[0-9.]')), // 基础过滤:只允许数字小数点 DecimalTextInputFormatter(), // 应用自定义逻辑 ], decoration: InputDecoration( labelText: '输入金额(小数点最多两位)', border: OutlineInputBorder(), ), // 可选:添加验证逻辑(例如在表单提交时) validator: (value) { if (value == null || value.isEmpty) { return '请输入数字'; } return null; }, ); } } ``` #### 关键逻辑解释 - **小数点唯一性检查**:使用`newValue.text.indexOf('.') != newValue.text.lastIndexOf('.')`确保输入中只有一个小数点。如果重复,返回旧值[^1]。 - **小数点后位数限制**:通过`substring`截取小数点后部分,检查长度是否超过2位(例如"1.123"会被阻止)。 - **首位0处理**:允许"0."或"0.12",但禁止"012"(通过`startsWith('0') && !startsWith('0.')`实现)。 - **正则基础过滤**:`FilteringTextInputFormatter.allow(RegExp(r'[0-9.]'))`确保输入只包含数字小数点,防止字母等非法字符[^2]。 - **键盘优化**:`keyboardType: TextInputType.numberWithOptions(decimal: true)`显示带小数点数字键盘,提升用户体验[^3]。 #### 注意事项 - **性能考虑**:自定义formatter在输入时实时校验,不影响性能。 - **边缘情况处理**:代码已处理空输入、单一输入(如"0")、和小数点开头(如".12")的情况。 - **集成到项目**:将`DecimalTextInputFormatter`类复制到您的项目中,无需额外依赖。 - **测试建议**:输入值如"123"、"0.12"、"12.34"会通过;"12.345"、"1.2.3"或"abc"会被阻止。 此方法基于Flutter官方推荐实践,结合了输入过滤和动态验证,确保输入安全用户友好[^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值