You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift3 iOS中UITextField仅允许数字和点并添加%符号的实现问题

解决方案:实时添加%符号并保持输入验证

看起来你已经搞定了数字和小数点的输入限制,接下来要实现编辑时自动添加%符号的话,核心是要避免重复添加%、保持光标位置正确,同时不破坏现有的验证逻辑。我帮你修改了代码,直接替换原方法即可:

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    // 处理删除操作:直接允许并同步更新文本与光标
    if string.isEmpty {
        let originalText = textField.text?.replacingOccurrences(of: " %", with: "") ?? ""
        let newNumberString = (originalText as NSString).replacingCharacters(in: range, with: string)
        // 空字符串时不显示%,否则重新添加
        textField.text = newNumberString.isEmpty ? "" : "\(newNumberString) %"
        // 把光标定位到数字末尾
        let cursorOffset = newNumberString.count
        if let cursorPosition = textField.position(from: textField.beginningOfDocument, offset: cursorOffset) {
            textField.selectedTextRange = textField.textRange(from: cursorPosition, to: cursorPosition)
        }
        return false
    }
    
    guard textField == self.questionTextFeild else { return true }
    
    do {
        // 先移除原文本中的%,避免干扰验证逻辑
        let originalText = textField.text?.replacingOccurrences(of: " %", with: "") ?? ""
        let newNumberString = (originalText as NSString).replacingCharacters(in: range, with: string)
        
        let expression = "^([0-9]+)?(\\.([0-9]{1,8})?)?$"
        let regex = try NSRegularExpression(pattern: expression, options: .caseInsensitive)
        let checkRange = NSRange(location: 0, length: newNumberString.utf16.count)
        let numberOfMatches = regex.numberOfMatches(in: newNumberString, options: [], range: checkRange)
        
        if numberOfMatches == 0 {
            return false
        }
        
        // 验证通过后,更新文本并添加%
        textField.text = "\(newNumberString) %"
        // 修正光标位置,确保在数字末尾(%前面)
        let cursorOffset = newNumberString.count
        if let cursorPosition = textField.position(from: textField.beginningOfDocument, offset: cursorOffset) {
            textField.selectedTextRange = textField.textRange(from: cursorPosition, to: cursorPosition)
        }
        
        // 返回false,因为我们已经手动处理了文本替换
        return false
    } catch {
        print("Regex error: \(error.localizedDescription)")
        return false
    }
}

关键细节说明:

  • 避免重复%:每次处理输入前都会移除原文本中的" %",确保无论怎么编辑,末尾只会保留一个%符号。
  • 光标体验优化:更新文本后自动把光标定位到数字部分的末尾,用户输入时不会被%符号干扰,操作更流畅。
  • 删除逻辑兼容:删除字符到空时,文本会自动清空,不会出现空的" %"占位。
  • 原验证逻辑保留:完全沿用你原来的正则规则,确保只能输入数字和最多一位小数点、小数点后最多8位数字。

测试一下这些场景:

  • 输入"1" → 实时显示"1 %",光标停在"1"后面
  • 输入"1.23" → 显示"1.23 %",光标停在"3"后面
  • 删除所有字符 → 文本清空
  • 输入"18.345" → 显示"18.345 %"

内容的提问来源于stack exchange,提问作者user2786

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:24:03