如何在Swift中实现TextField输入数字时每3位自动添加‘.’
嘿,这个需求其实挺常见的,我之前做金融类APP的时候也实现过类似的功能。核心是借助UITextFieldDelegate来拦截输入,然后对文本进行格式化处理,同时要特别注意光标位置的维护,不然用户输入体验会很差。下面是具体的实现步骤和代码:
实现思路
- 拦截TextField的输入/删除操作,获取即将显示的新文本
- 移除新文本中所有非数字字符(包括已有的分隔符)
- 对纯数字字符串进行格式化:从右往左每3位添加一个
.分隔符 - 更新TextField的文本,并调整光标到正确的位置,避免光标乱跑
具体代码
1. 数字格式化辅助函数
先写一个通用的格式化函数,负责把纯数字字符串转换成带.分隔的格式:
func formatNumberWithDotSeparator(_ input: String) -> String { // 移除所有非数字字符,只保留数字 let cleanDigits = input.components(separatedBy: CharacterSet.decimalDigits.inverted).joined() // 如果没有数字,直接返回空字符串 guard !cleanDigits.isEmpty else { return "" } // 反转字符串,方便从右往左分割(因为分隔符是从个位开始每3位加) let reversedDigits = String(cleanDigits.reversed()) // 按每3位分割成数组 let digitChunks = stride(from: 0, to: reversedDigits.count, by: 3).map { let startIndex = reversedDigits.index(reversedDigits.startIndex, offsetBy: $0) let endIndex = reversedDigits.index(startIndex, offsetBy: 3, limitedBy: reversedDigits.endIndex) ?? reversedDigits.endIndex return String(reversedDigits[startIndex..<endIndex]) } // 把分割后的数组用`.`连接,再反转回原来的顺序 return digitChunks.joined(separator: ".").reversed() }
2. 实现UITextFieldDelegate方法
在你的ViewController或者自定义TextField类中,实现代理方法来处理输入:
class YourViewController: UIViewController, UITextFieldDelegate { @IBOutlet weak var numberTextField: UITextField! override func viewDidLoad() { super.viewDidLoad() // 设置TextField的代理 numberTextField.delegate = self // 设置键盘为数字键盘,避免用户输入非数字字符(可选,但能提升体验) numberTextField.keyboardType = .numberPad } func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { guard let currentText = textField.text else { return true } // 计算输入后的新文本(包含当前输入/删除的内容) let newText = (currentText as NSString).replacingCharacters(in: range, with: string) // 对新文本进行格式化 let formattedText = formatNumberWithDotSeparator(newText) // 如果格式化后的文本和原新文本不同,说明需要更新TextField内容 if formattedText != newText { textField.text = formattedText // 计算光标应该在的位置,避免光标跳到末尾 // 先算出用户输入/删除前的光标位置对应的新文本中的位置 let cursorOffsetInNewText = newText.count - (currentText.count - range.location) // 再转换为格式化后文本中的光标位置 let cursorOffsetInFormattedText = formattedText.count - (newText.count - cursorOffsetInNewText) // 设置光标位置 if let targetPosition = textField.position(from: textField.beginningOfDocument, offset: cursorOffsetInFormattedText) { textField.selectedTextRange = textField.textRange(from: targetPosition, to: targetPosition) } // 返回false,因为我们已经手动更新了TextField内容 return false } // 如果不需要格式化,直接允许输入 return true } }
注意事项
- 键盘类型设置:把TextField的
keyboardType设为.numberPad,可以让用户只能输入数字,减少非数字字符的处理压力,当然代码里也做了过滤,双重保障。 - 光标位置处理:这是很容易忽略的点,如果不处理光标,用户输入时光标会直接跳到末尾,体验非常差。上面的代码通过计算偏移量,保证光标始终在用户输入的位置附近。
- 删除操作兼容:代码已经考虑了删除字符的情况,无论是删除单个字符还是选中一段删除,格式化和光标位置都能正常工作。
内容的提问来源于stack exchange,提问作者afi permana
相关产品推荐
相关产品推荐

