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

如何在Swift中实现TextField输入数字时每3位自动添加‘.’

嘿,这个需求其实挺常见的,我之前做金融类APP的时候也实现过类似的功能。核心是借助UITextFieldDelegate来拦截输入,然后对文本进行格式化处理,同时要特别注意光标位置的维护,不然用户输入体验会很差。下面是具体的实现步骤和代码:

实现思路
  1. 拦截TextField的输入/删除操作,获取即将显示的新文本
  2. 移除新文本中所有非数字字符(包括已有的分隔符)
  3. 对纯数字字符串进行格式化:从右往左每3位添加一个.分隔符
  4. 更新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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 21:19:05