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
相关产品推荐
相关产品推荐

