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

Swift3 iOS中如何为UITextField的shouldChangeCharactersIn设置多条件

整合UITextField输入校验条件的实现方案

我来帮你把这四个输入校验条件完整整合到shouldChangeCharactersIn方法里,先看完整的实现代码,之后再逐个拆解说明每个条件是怎么满足的:

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    // 获取当前文本(处理NSRange转Swift字符串范围)
    guard let currentText = textField.text else { return true }
    let updatedText = (currentText as NSString).replacingCharacters(in: range, with: string)
    
    // 条件1:仅允许输入数字和$,过滤非法字符
    let allowedCharacters = CharacterSet(charactersIn: "0123456789$")
    let inputCharacterSet = CharacterSet(charactersIn: string)
    if !inputCharacterSet.isSubset(of: allowedCharacters) {
        return false
    }
    
    // 条件3:$只能出现一次,且不能作为开头
    let dollarSignCount = updatedText.components(separatedBy: "$").count - 1
    if dollarSignCount > 1 {
        return false
    }
    // 检查是否把$放在开头(包括直接输入$当第一个字符,或者替换后开头是$)
    if updatedText.hasPrefix("$") {
        return false
    }
    
    // 条件4:$之后不能输入数字
    if let dollarIndex = updatedText.firstIndex(of: "$") {
        // 获取$之后的部分,如果新输入的内容落在$之后,且是数字的话拦截
        let dollarUtf16Offset = dollarIndex.utf16Offset(in: updatedText)
        let isInputAfterDollar = range.location > dollarUtf16Offset
        let isInputDigit = !string.rangeOfCharacter(from: .decimalDigits)?.isEmpty ?? false
        
        if isInputAfterDollar && isInputDigit {
            // 弹出错误提示
            let alert = UIAlertController(title: "Error", message: "Number format is incorrect", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "OK", style: .default))
            // 适配iOS 13+的控制器获取方式,可根据项目结构调整
            if let topVC = UIApplication.shared.connectedScenes
                .filter({$0.activationState == .foregroundActive})
                .compactMap({$0 as? UIWindowScene})
                .first?.windows
                .filter({$0.isKeyWindow}).first?.rootViewController {
                topVC.present(alert, animated: true)
            }
            return false
        }
    }
    
    // 条件2:添加千分位逗号(只处理$之前的数字部分)
    if let dollarIndex = currentText.firstIndex(of: "$") {
        // 如果已有$,只格式化$之前的数字部分
        let numberPart = String(currentText[..<dollarIndex])
        let cleanedNumberPart = numberPart.replacingOccurrences(of: ",", with: "")
        // 处理新输入:如果是在$之前输入,重新格式化数字部分
        let dollarCurrentUtf16Offset = dollarIndex.utf16Offset(in: currentText)
        if range.location <= dollarCurrentUtf16Offset {
            let newNumberPart = (cleanedNumberPart as NSString).replacingCharacters(in: range, with: string)
            let formatter = NumberFormatter()
            formatter.numberStyle = .decimal
            formatter.locale = Locale.current
            formatter.maximumFractionDigits = 0
            if let number = formatter.number(from: newNumberPart), let formattedNumber = formatter.string(from: number) {
                textField.text = "\(formattedNumber)$"
                return false
            }
        }
    } else {
        // 还没有$,格式化整个输入的数字
        let cleanedText = currentText.replacingOccurrences(of: ",", with: "")
        let newCleanedText = (cleanedText as NSString).replacingCharacters(in: range, with: string)
        let formatter = NumberFormatter()
        formatter.numberStyle = .decimal
        formatter.locale = Locale.current
        formatter.maximumFractionDigits = 0
        if let number = formatter.number(from: newCleanedText), let formattedText = formatter.string(from: number) {
            textField.text = formattedText
            return false
        }
    }
    
    return true
}

逐个校验条件的实现说明:

  • 条件1:仅允许数字和$:通过CharacterSet判断输入的字符是否都在允许的集合里,非法字符直接返回false拦截。
  • 条件2:千分位逗号格式化:分两种情况处理——还没输入$时,格式化整个数字;已经输入$后,只格式化$之前的数字部分,保留$在末尾。每次输入时先去掉已有逗号,重新拼接后用NumberFormatter生成带千分位的字符串,直接设置给textField并返回false(因为我们自己处理了文本更新)。
  • 条件3:$的规则校验:统计更新后的文本中$的数量,超过1个直接拦截;同时检查更新后的文本是否以$开头,是的话也拦截,确保$只能出现在数字之后。
  • 条件4:$后不能输入数字:先找到$的位置,判断新输入的内容是否落在$之后且是数字,如果是就弹出错误提示并拦截输入。

注意:弹出提示的控制器获取逻辑适配了iOS 13+的SceneDelegate场景,你可以根据自己项目的结构灵活调整这部分代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:41:31