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

Swift中UITextField实时转百分比格式化退格键失效问题求解

问题根因

当光标位于末尾%右侧时按下退格键,系统会先删除最后一个字符%,此时输入框临时文本为不带%的纯数字串。你的格式化方法会自动将纯数字再次补回%,且数字本身未发生变化,最终文本和修改前完全一致,看起来就像删除操作未生效。

解决方案

需要从三个方面调整代码:

1. 修正字符串格式化扩展

删除强制返回0%的逻辑,当纯数字为空时直接返回空字符串,避免删到最后一位时强制回弹为0%:

func percentInputFormatting() -> String {
    let formatter = NumberFormatter()
    formatter.numberStyle = .decimal
    formatter.maximumFractionDigits = 2
    formatter.minimumFractionDigits = 2
    
    // 过滤所有非数字字符
    let regex = try! NSRegularExpression(pattern: "[^0-9]", options: .caseInsensitive)
    let pureNumberStr = regex.stringByReplacingMatches(in: self, options: [], range: NSMakeRange(0, self.count), withTemplate: "")
    
    // 纯数字为空直接返回空
    guard !pureNumberStr.isEmpty else {
        return ""
    }
    
    let double = (pureNumberStr as NSString).doubleValue
    let number = NSNumber(value: double / 100)
    
    guard let formattedStr = formatter.string(from: number) else {
        return "0%"
    }
    return "\(formattedStr)%"
}

2. 处理末尾退格特殊场景

给UITextField设置代理,实现shouldChangeCharactersIn方法,拦截光标在末尾时的退格操作,主动删除最后一位数字:

// 先给输入框设置代理
cell.textField.delegate = self

// 实现代理方法
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    // 匹配:退格操作 + 光标在最后一位 + 当前文本以%结尾
    if string.isEmpty, 
       let currentText = textField.text, 
       currentText.hasSuffix("%"),
       range.location == currentText.count - 1 {
        // 提取纯数字并删除最后一位后重新格式化
        let regex = try! NSRegularExpression(pattern: "[^0-9]", options: .caseInsensitive)
        var pureNumberStr = regex.stringByReplacingMatches(in: currentText, options: [], range: NSMakeRange(0, currentText.count), withTemplate: "")
        pureNumberStr = String(pureNumberStr.dropLast(1))
        textField.text = pureNumberStr.percentInputFormatting()
        return false
    }
    return true
}

3. 优化光标位置(可选,提升体验)

在输入变更回调中,格式化完成后自动将光标移动到%符号前,避免用户每次都要手动移动光标:

@objc func textChangedIntoPercent (sender : UITextField) {
    if let amountString = sender.text?.percentInputFormatting() {
        sender.text = amountString
        // 将光标定位到%前面
        if let position = sender.position(from: sender.endOfDocument, offset: -1) {
            sender.selectedTextRange = sender.textRange(from: position, to: position)
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 09:15:04