忽略设备区域设置,将DecimalPad数字键盘的逗号改为句号
嗨,我之前也踩过这个DecimalPad分隔符的坑!子类化重写textInputMode确实不太好使,系统很多时候会忽略这个重写的属性,毕竟键盘布局的优先级是系统区域设置 > app语言设置 > 我们自定义的textInputMode。给你几个亲测有效的解决方案,按需选择:
方案1:拦截输入替换字符(简单快速)
这个方法不用改键盘显示,而是在用户输入时把逗号自动替换成句号,体验上也很顺畅。只需要给UITextField设置delegate,然后实现shouldChangeCharactersIn方法:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { // 把输入的逗号替换成句号 let adjustedString = string.replacingOccurrences(of: ",", with: ".") guard let currentText = textField.text, let textRange = Range(range, in: currentText) else { return true } // 手动更新文本,阻止系统默认输入行为 textField.text = currentText.replacingCharacters(in: textRange, with: adjustedString) return false }
优点是代码量少,快速生效;缺点是键盘上还是显示逗号,但用户输入后会立刻变成句号,大部分场景下足够用了。
方案2:强制设置固定Locale(让键盘直接显示句号)
试试给你的UITextField设置一个固定的Locale,比如en_US_POSIX——这个Locale是独立于系统区域设置的,专门用于格式化和输入的固定标准,不会随用户设备设置变化:
override func viewDidLoad() { super.viewDidLoad() // 给目标TextField设置固定Locale yourDecimalTextField.locale = Locale(identifier: "en_US_POSIX") }
这个方法能直接让DecimalPad显示句号,但要注意:如果你的App有严格的语言绑定(比如只支持意大利语),最好测试一下是否会和App语言设置冲突,不过en_US_POSIX通常不会受App语言影响,是个比较稳妥的选择。
方案3:自定义Decimal键盘(完全可控)
如果上面两个方案都达不到你的要求,那自定义键盘就是终极解决方案——完全脱离系统键盘的限制,自己做一个带句号的数字键盘:
// 在viewDidLoad里创建自定义键盘 override func viewDidLoad() { super.viewDidLoad() let customKeyboard = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: 220)) customKeyboard.backgroundColor = .systemGray5 // 添加数字按钮和句号按钮(这里简化布局,实际可以用StackView排版) let periodBtn = UIButton(type: .system) periodBtn.setTitle(".", for: .normal) periodBtn.titleLabel?.font = UIFont.systemFont(ofSize: 24) periodBtn.addTarget(self, action: #selector(onPeriodTapped), for: .touchUpInside) periodBtn.frame = CGRect(x: customKeyboard.frame.width - 60, y: customKeyboard.frame.height - 60, width: 60, height: 60) customKeyboard.addSubview(periodBtn) // 给TextField设置自定义键盘 yourDecimalTextField.inputView = customKeyboard } // 句号按钮点击事件 @objc func onPeriodTapped() { guard let currentText = yourDecimalTextField.text else { yourDecimalTextField.text = "." return } // 避免重复添加句号 if !currentText.contains(".") { yourDecimalTextField?.text?.append(".") } }
这个方案完全可控,不管系统怎么设置,键盘上都是你想要的句号,就是需要自己处理按钮布局和输入逻辑,稍微麻烦一点,但胜在稳定。
至于你说的子类化重写textInputMode没用的原因:系统的textInputMode更多是给系统提供输入上下文的,重写这个属性时,系统会优先考虑App的语言设置和设备区域,很多时候不会采纳我们自定义的返回值,所以这个方法基本行不通。
内容的提问来源于stack exchange,提问作者user5273262

