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

iOS Swift:OTP式手机号输入框空值退格焦点跳转问题处理

解决OTP输入框空状态下退格键跳转问题

问题根源

当前代码依赖输入框文本内容判断退格键,当输入框为空时,文本为空字符串,导致退格键的判断逻辑失效,无法触发跳转到上一个输入框的操作。

优化方案

通过数组统一管理输入框,简化索引操作;在shouldChangeCharactersIn方法中准确处理输入和退格场景,尤其是空输入框的退格逻辑。

完整修改代码

@IBOutlet weak var textFieldNumber1: UITextField!
@IBOutlet weak var textFieldNumber2: UITextField!
@IBOutlet weak var textFieldNumber3: UITextField!
@IBOutlet weak var textFieldNumber4: UITextField!
@IBOutlet weak var textFieldNumber5: UITextField!
@IBOutlet weak var textFieldNumber6: UITextField!
@IBOutlet weak var textFieldNumber7: UITextField!
@IBOutlet weak var textFieldNumber8: UITextField!
@IBOutlet weak var textFieldNumber9: UITextField!
@IBOutlet weak var textFieldNumber10: UITextField!
@IBOutlet weak var textFieldPassword: UITextField!

private var otpTextFields: [UITextField]!
private var counterTextFieldPhoneNumber = 0

func setupTextFields() {
    // 将输入框整理为数组,方便索引操作
    otpTextFields = [textFieldNumber1, textFieldNumber2, textFieldNumber3, textFieldNumber4, textFieldNumber5,
                     textFieldNumber6, textFieldNumber7, textFieldNumber8, textFieldNumber9, textFieldNumber10].compactMap { $0 }
    
    otpTextFields.forEach { tf in
        tf.keyboardType = .numberPad
        tf.delegate = self
        tf.tag = otpTextFields.firstIndex(of: tf)! + 1 // 保持tag从1开始,兼容原有逻辑
    }
}

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    // 处理数字输入:仅允许单个数字字符
    if !string.isEmpty {
        guard textField.text?.isEmpty ?? true else { return false } // 已有内容时不允许重复输入
        
        textField.text = string
        counterTextFieldPhoneNumber += 1
        
        // 跳转到下一个输入框(如果不是最后一个)
        let currentIndex = otpTextFields.firstIndex(of: textField)!
        if currentIndex < otpTextFields.count - 1 {
            otpTextFields[currentIndex + 1].becomeFirstResponder()
        } else {
            // 最后一个输入框完成,收起键盘并拼接手机号
            textField.resignFirstResponder()
            let phoneNumber = otpTextFields.compactMap { $0.text }.joined()
            viewModel.phoneNumber = phoneNumber
        }
        return false
    } else {
        // 处理退格键操作
        if textField.text?.isEmpty ?? true {
            // 当前输入框为空,跳转到上一个输入框(如果存在)
            let currentIndex = otpTextFields.firstIndex(of: textField)!
            if currentIndex > 0 {
                let previousTF = otpTextFields[currentIndex - 1]
                previousTF.text = ""
                previousTF.becomeFirstResponder()
                counterTextFieldPhoneNumber = max(0, counterTextFieldPhoneNumber - 1)
            } else {
                // 第一个输入框为空,退格不触发跳转,仅修正计数器
                counterTextFieldPhoneNumber = max(0, counterTextFieldPhoneNumber - 1)
            }
        } else {
            // 当前输入框有内容,清空内容并修正计数器
            textField.text = ""
            counterTextFieldPhoneNumber = max(0, counterTextFieldPhoneNumber - 1)
        }
        return false
    }
}

关键改进点

  • 数组化管理输入框:替代大量switch分支,通过索引直接定位上/下一个输入框,代码更简洁易维护。
  • 精准退格判断:通过replacementString.isEmpty判断退格操作,不受输入框是否为空的影响,逻辑更可靠。
  • 空输入框退格处理:空输入框触发退格时,自动跳转到上一个输入框并清空其内容(如需保留内容可移除previousTF.text = ""),符合用户操作习惯。
  • 简化输入逻辑:输入单个数字后自动跳转下一个输入框,最后一个输入完成后自动收起键盘并拼接手机号。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 09:03:49