如何同时校验所有UITextField输入,仅当全部有内容时才启用按钮?
问题根因
- 原有代码未区分触发代理的输入框,无论密码框还是确认密码框触发输入事件,都直接用当前事件的range去计算确认密码框的修改后文本。两个输入框都设置代理时,密码框的range和确认密码框的文本长度不匹配,会触发越界崩溃。
- 原有逻辑仅校验确认密码框的输入变化,未监听密码框的内容变更,因此密码框清空时不会触发按钮状态更新。
解决方案
推荐使用输入事件监听实现,无需处理代理适配,逻辑更稳定:
步骤1:在viewDidLoad中添加输入监听
override func viewDidLoad() { super.viewDidLoad() // 给两个输入框绑定编辑变化事件 tfPassword.addTarget(self, action: #selector(textFieldContentChanged), for: .editingChanged) tfConfirmPassword.addTarget(self, action: #selector(textFieldContentChanged), for: .editingChanged) // 初始化按钮为不可用状态 updateButtonStatus() }
步骤2:实现输入变化回调与统一状态校验逻辑
// 输入框内容变化时触发 @objc private func textFieldContentChanged() { updateButtonStatus() } // 统一校验两个输入框,更新按钮状态 private func updateButtonStatus() { // 去掉前后空白字符校验,避免用户输入空格误判 let passwordNotEmpty = !(tfPassword.text?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true) let confirmPwdNotEmpty = !(tfConfirmPassword.text?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true) // 可根据需求扩展校验规则,比如新增两次密码一致校验: // let pwdMatch = tfPassword.text == tfConfirmPassword.text // let enableButton = passwordNotEmpty && confirmPwdNotEmpty && pwdMatch let enableButton = passwordNotEmpty && confirmPwdNotEmpty btnContinue.isEnabled = enableButton btnContinue.backgroundColor = enableButton ? UIColor(named: "accentColor") : UIColor(named: "labelColor") }
可选:代理实现方案
如果需要通过shouldChangeCharactersIn代理做输入拦截(比如限制输入长度、禁止特殊字符),可使用以下修正后的代理代码,和上述updateButtonStatus方法配合使用即可:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { // 计算当前输入框修改后的文本 let originText = textField.text ?? "" guard let range = Range(range, in: originText) else { return false } let finalText = originText.replacingCharacters(in: range, with: string) // 示例:限制输入长度不超过16位 if finalText.count > 16 { return false } // 等待文本更新完成后刷新按钮状态 DispatchQueue.main.async { self.updateButtonStatus() } return true }
内容的提问来源于stack exchange,提问作者Mel
相关产品推荐
相关产品推荐

