如何实现UITextField输入时保留部分占位符的效果?
解决方案
问题出在输入框的文本范围和占位符字符串的字符索引不匹配——占位符包含分隔空格,而输入框的实际输入文本没有这些空格,直接用输入框的NSRange去映射占位符字符串的位置,自然会偏移出错。
以下是修正后的实现思路和代码:
核心逻辑
- 先过滤输入的字符,只保留数字,然后生成带分隔符的格式化文本(比如
1234567890→123 456 7890) - 根据格式化后的文本,生成占位符字符串:已输入的数字保留,未填充的位置用下划线替换,分隔符位置保持空格
- 同步更新占位符Label的文本,同时控制输入框的显示(让输入框文本透明,只展示占位符Label的内容)
完整代码实现
// 定义格式化模板(对应最终的格式:3位 + 空格 + 3位 + 空格 + 4位) let formatTemplate = "XXX XXX XXXX" var placeholderLabel = UILabel() // 初始化占位符Label的方法 func setupPlaceholderLabel(in textField: UITextField) { placeholderLabel.text = formatTemplate.replacingOccurrences(of: "X", with: "_") placeholderLabel.sizeToFit() textField.addSubview(placeholderLabel) placeholderLabel.textColor = .gray placeholderLabel.font = textField.font // 对齐输入框的文本位置(根据输入框内边距调整) placeholderLabel.frame = CGRect(x: textField.textInsets.left, y: (textField.bounds.height - placeholderLabel.bounds.height)/2, width: placeholderLabel.bounds.width, height: placeholderLabel.bounds.height) // 让输入框文本不可见,只显示占位符Label textField.textColor = textField.backgroundColor } // UITextField代理方法 func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { // 1. 获取当前输入框文本,过滤非数字字符 guard let currentText = textField.text?.replacingOccurrences(of: " ", with: "") else { return true } let newText: String if string.isEmpty { // 删除字符:移除对应位置的内容 newText = currentText.replacingCharacters(in: Range(range, in: currentText)!, with: "") } else { // 输入字符:只保留数字 let filteredString = string.filter { $0.isNumber } newText = currentText + filteredString } // 限制最大长度(对应模板的10位数字) guard newText.count <= 10 else { return false } // 2. 生成带分隔符的格式化文本 var formattedText = "" for (index, char) in newText.enumerated() { formattedText.append(char) // 在第3位和第6位后添加空格分隔符 if index == 2 || index == 5 { formattedText.append(" ") } } // 3. 生成占位符字符串:用格式化文本替换模板中的X,剩余X换成下划线 var placeholderString = formatTemplate for (index, char) in formattedText.enumerated() { if char != " " { placeholderString.replaceSubrange(placeholderString.index(placeholderString.startIndex, offsetBy: index)..<placeholderString.index(placeholderString.startIndex, offsetBy: index+1), with: String(char)) } } placeholderString = placeholderString.replacingOccurrences(of: "X", with: "_") // 4. 更新占位符Label和输入框文本 placeholderLabel.text = placeholderString textField.text = formattedText return false // 手动处理了文本更新,阻止系统默认行为 }
关键说明
- 用
formatTemplate统一格式规则,后续修改格式只需调整模板即可 - 输入处理时先过滤非数字,再生成带分隔符的文本,确保和占位符字符串的索引完全对齐
- 让输入框文本颜色与背景色一致,仅展示占位符Label的内容,完美实现“输入数字替换下划线”的视觉效果
- 代理方法返回
false,避免系统默认文本更新逻辑干扰自定义处理
内容的提问来源于stack exchange,提问作者Tolgay Toklar
相关产品推荐
相关产品推荐

