【问题标题】:What is the best way to enter numeric values with decimal points?输入带小数点的数值的最佳方法是什么?
【发布时间】:2010-09-21 12:59:16
【问题描述】:

在我的应用中,用户需要能够输入带小数位的数值。 iPhone 不提供专门用于此目的的键盘 - 仅提供数字键盘和带有数字和符号的键盘。

有没有一种简单的方法来使用后者并防止输入任何非数字输入而无需正则表达式最终结果?

谢谢!

【问题讨论】:

    标签: iphone cocoa-touch


    【解决方案1】:

    根据具体的应用程序,在 iphone 上提供一个可供用户选择位置的滑块可能是更好的选择。那么根本不需要输入数字。

    【讨论】:

      【解决方案2】:

      您可能希望使用滑块(如 Martin v. Löwis 所建议的那样)或 UIPickerView,每个数字都有一个单独的轮子。​​

      【讨论】:

        【解决方案3】:

        我想做完全相同的事情,除了使用货币而不是直接的十进制值。

        我最终创建了一个包含 UITextField 和 UILabel 的自定义视图。标签覆盖了文本字段,但文本字段仍会收到触摸。我使用 UITextFieldTextDidChange 通知来观察文本字段的变化(我使用 NSNumberFormatter 将结果数字转换为格式化的货币值)来更新标签。

        要禁用允许用户重新定位插入点的放大镜,您需要使用自定义 UITextField 子类并覆盖 touchesBegan:withEvent: 并将其设置为不执行任何操作。

        我的解决方案可能与您需要的不同,因为小数点始终是固定的——我使用系统的货币设置来确定小数点后应该有多少位数。但是,数字小键盘上没有小数点。而且您无法在键盘上添加任何按钮(这尤其令人讨厌,因为键盘左下角有一个空白按钮非常适合小数点!)所以我没有解决方案,很遗憾。

        【讨论】:

        • 我做过类似的事情,除了自定义视图。当它收到触摸时,我在屏幕底部(键盘后面)设置了一个文本字段并在其上调用becomeFirstResponder。这样我就不用担心禁用放大镜了。
        • 你对光标做了什么?
        【解决方案4】:

        一个更优雅的解决方案恰好也是最简单的。

        您不需要小数分隔键

        为什么?因为你可以简单地从用户的输入中推断出来。例如,在美国地区,当您输入 1.23 美元时,您首先输入数字 1-2-3(按该顺序)。在系统中,每输入一个字符,就会被识别为:

        • 用户输入 1:$0.01
        • 用户输入 2:$0.12
        • 用户输入 3:$1.23

        请注意我们如何根据用户的输入推断小数点分隔符。现在,如果用户想要输入 1.00 美元,他们只需输入数字 1-0-0。

        为了让您的代码处理不同区域设置的货币,您需要获取货币的最大小数位数。这可以通过以下代码 sn-p 来完成:

        NSNumberFormatter *currencyFormatter = [[NSNumberFormatter alloc] init];
        [currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
        int currencyScale = [currencyFormatter maximumFractionDigits];
        

        例如,日元的最大小数位数为 0。因此,在处理日元输入时,没有小数分隔符,因此甚至不必担心小数。

        这种解决问题的方法允许您使用 Apple 提供的库存数字输入键盘,而无需担心自定义键盘、正则表达式验证等。

        【讨论】:

        • 只是为了确保 - 不要使用浮点数作为货币!
        • 我还为感兴趣的人写了一篇关于此的博客文章:blog.weareuproar.com/?p=11
        • 一点 - 不幸的是,iPhone SDK UIControl 不支持 setFormatter 方法来允许您将 NSFormatter 附加到 UITextField 或其他 UIControl(等效的 Cocoa NSControl 确实支持 setFormatter)。我就此向 Apple 提出了增强问题 (#5847381)。
        • 最初的问题没有提到货币,但这个答案几乎假设我们要输入货币。如果您想接受任意浮点输入,这将无济于事。
        • 作为一个用户,如果我想输入一个通用的小数值或货币值,我觉得必须输入 100 是一件很烦人的事情。例如,对于货币,如果应用程序提示我输入金额,我希望以美元、欧元或日元输入,而不是美分(即 100 美元或欧元)。因此,我希望能够输入“1”来表示 1 美元。您的建议迫使用户仔细检查输入“1”实际上没有输入 $1 而是 $.01。这通常不是用户所期望的。
        【解决方案5】:

        这是已接受答案中建议的解决方案的示例。这不处理其他货币或任何东西 - 在我的情况下,我只需要支持美元,无论语言环境/货币是什么,所以这对我来说没问题:

        -(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range
            replacementString:(NSString *)string {
        
            double currentValue = [textField.text doubleValue];
            //Replace line above with this
            //double currentValue = [[textField text] substringFromIndex:1] doubleValue];
            double cents = round(currentValue * 100.0f);
        
            if ([string length]) {
                for (size_t i = 0; i < [string length]; i++) {
                    unichar c = [string characterAtIndex:i];
                    if (isnumber(c)) {
                        cents *= 10;
                        cents += c - '0'; 
                    }            
                }
            } else {
                // back Space
                cents = floor(cents / 10);
            }
        
            textField.text = [NSString stringWithFormat:@"%.2f", cents / 100.0f];
            //Add this line
            //[textField setText:[NSString stringWithFormat:@"$%@",[textField text]]];
            return NO;
        }
        

        四舍五入和楼层很重要 a) 因为浮点表示有时会丢失 .00001 或其他任何内容,并且 b) 格式字符串会向上舍入我们在退格部分删除的任何精度。

        【讨论】:

        • 这段代码在输入第15个数字后似乎不起作用。我输入 999999999999999 然后在接下来的 9 上,输出是 100000000000000.00
        • 您正在失去精度,因为它使用浮点数。
        • 我稍微修改了您的算法,以便将一小部分一美分存入我的离岸账户。它已经在工作了。哇哈哈。
        【解决方案6】:

        我构建了一个带小数点的自定义数字键盘视图控制器...检查一下:

        http://sites.google.com/site/psychopupnet/iphone-sdk/tenkeypadcustom10-keypadwithdecimal

        【讨论】:

          【解决方案7】:

          从 iOS4.1 开始,有一个新的键盘类型 UIKeyboardTypeNumberPad,但不幸的是,到目前为止,它似乎还没有出现在 Interface Builder 选择列表中。

          【讨论】:

            【解决方案8】:

            以下是如何在不使用与货币无关的方式中使用浮点数、round() 或 ceil() 的情况下做到这一点。

            在您的视图控制器中,设置以下实例变量(如果这是您的包,请使用关联的@property 语句):

            @interface MyViewController : UIViewController <UITextFieldDelegate> {
            @private
                UITextField *firstResponder;
                NSNumberFormatter *formatter;
                NSInteger currencyScale;
                NSString *enteredDigits;
            }
            
            @property (nonatomic, readwrite, assign) UITextField *firstResponder;
            @property (nonatomic, readwrite, retain) NSNumberFormatter *formatter;
            @property (nonatomic, readwrite, retain) NSString *enteredDigits;
            
            @end
            

            您的 viewDidLoad 方法应包含以下内容:

            - (void)viewDidLoad {
                [super viewDidLoad];
            
                NSNumberFormatter *aFormatter = [[NSNumberFormatter alloc] init];
                [aFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
                currencyScale = -1 * [aFormatter maximumFractionDigits];
                self.formatter = aFormatter;
                [aFormatter release];
            }
            

            然后按如下方式实现您的 UITextFieldDelegate 方法:

            #pragma mark -
            #pragma mark UITextFieldDelegate methods
            
            - (void)textFieldDidBeginEditing:(UITextField *)textField {
                // Keep a pointer to the field, so we can resign it from a toolbar
                self.firstResponder = textField;
                self.enteredDigits = @"";
            }
            
            - (void)textFieldDidEndEditing:(UITextField *)textField {
                if ([self.enteredDigits length] > 0) {
                    // Get the amount
                    NSDecimalNumber *result = [[NSDecimalNumber decimalNumberWithString:self.enteredDigits] decimalNumberByMultiplyingByPowerOf10:currencyScale];
                    NSLog(@"result: %@", result);
                }
            }
            
            - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
            
                // Check the length of the string
                if ([string length]) {
                    self.enteredDigits = [self.enteredDigits stringByAppendingFormat:@"%d", [string integerValue]];
                } else {
                    // This is a backspace
                    NSUInteger len = [self.enteredDigits length];
                    if (len > 1) {
                        self.enteredDigits = [self.enteredDigits substringWithRange:NSMakeRange(0, len - 1)];
                    } else {
                        self.enteredDigits = @"";
                    }
                }
            
                NSDecimalNumber *decimal = nil;
            
                if ( ![self.enteredDigits isEqualToString:@""]) {
                    decimal = [[NSDecimalNumber decimalNumberWithString:self.enteredDigits] decimalNumberByMultiplyingByPowerOf10:currencyScale];
                } else {
                    decimal = [NSDecimalNumber zero];
                }
            
                // Replace the text with the localized decimal number
                textField.text = [self.formatter stringFromNumber:decimal];
            
                return NO;  
            }
            

            只用英镑和便士对此进行了测试,但它也应该适用于日元。如果您想为非货币目的格式化小数,那么只需阅读NSNumberFormatter 上的文档并设置您想要的任何格式/maximumFractionDigits。

            【讨论】:

            • 消除self.formatter = [[NSNumberFormatter alloc] init];的泄漏
            • 这似乎有效。但是在第 15 位之后,它会被四舍五入。我开始认为真正的解决方案是永远不要转换字符串。但只需添加格式。
            • 我只是限制了可以添加的位数。这完美地工作。还有一个很好的提示:如果您要预先填充 UITextfield,您需要设置输入的数字字符串以反映您添加的内容。然后一切正常。此外,我只需要 textField 应该更改CharectersInRange 委托方法来完成这项工作。
            【解决方案9】:

            我认为最好指出从 iOS 4.1 开始您可以使用新的UIKeyboardTypeDecimalPad

            所以现在你只需要:

            myTextField.keyboardType=UIKeyboardTypeDecimalPad;
            

            【讨论】:

            • 谢谢!为什么界面生成器没有这个选项?即使在 Xcode4 中也不存在...
            • 在 Xcode 4.0.2 中,我相信它被称为“数字和标点符号”。
            • @Thomas 不,不是。那是一个不同的键盘
            • 有这样的东西可以让用户输入负数吗?
            【解决方案10】:

            Mike Weller 帖子的 Swift 2 实现,也只有美元:

             func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
                guard let str = textField.text else {
                    textField.text = "0.00"
                    return false
                }
            
                let value = (str as NSString).doubleValue
            
                var cents = round(value * 100)
                if string.characters.count > 0 {
                    for c in string.characters {
                        if let num = Int(String(c)) {
                            cents *= 10
                            cents += Double(num)
                        }
                    }
                }
                else {
                    cents = floor(cents / 10)
                }
            
                textField.text = NSString(format: "%.2f", cents/100) as String
            
                return false
            }
            

            【讨论】:

              【解决方案11】:

              您可以使用STATextField 并将currencyRepresentation 设置为YES:

              确保输入的小数点不超过一位,并且小数点右侧不超过两位。

              还有STAATMTextField默认支持货币模式 ATM文本输入:

              提供一个模拟 ATM 机输入行为的文本字段。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2010-10-27
                • 1970-01-01
                • 2021-03-16
                • 1970-01-01
                • 2018-05-21
                • 2010-10-07
                • 1970-01-01
                相关资源
                最近更新 更多