Swift:如何在静态类中实现UIAlertController多输入框非空启用按钮
解决UIAlertController登录按钮仅在双输入框非空时启用的问题
问题场景
使用Swift 5、Xcode 14.2开发,两个UIViewController需要复用同一个登录弹窗,为避免重复代码,将弹窗创建逻辑放在单线程访问的静态类中。当前问题是登录按钮无论输入框是否为空都会关闭弹窗,需求是仅当用户名和密码输入框都有内容时,才启用登录按钮。
现有代码
静态类中的弹窗创建代码
static func createLoginDialog(buttonPressed: @escaping (_ username:String, _ pw:String) -> Void) -> UIAlertController { let alert = UIAlertController(title: "Login", message: "", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "Log in", style: .default, handler: { (action: UIAlertAction!) in let u = alert.textFields![0].text! let p = alert.textFields![1].text! buttonPressed(u,p) })) alert.addTextField { textField in textField.placeholder = "Enter Username" } alert.addTextField { textField in textField.placeholder = "Enter Password" } return alert }
UIViewController中的调用代码
func doSomethingAndShowAlert() { //Do something let alert = MyStaticClass.createLoginDialog() { (username,pw) in //Do stuff with non-empty input } self.present(alert,animated: true, completion: nil) }
解决方案
核心思路是:先禁用登录按钮,给两个输入框添加内容变更监听,实时检查输入有效性,满足条件时启用按钮。无需使用@objc/selector的复杂绑定,通过userInfo传递实例,配合静态类的@objc方法即可实现需求。
修改后的静态类代码如下:
static func createLoginDialog(buttonPressed: @escaping (_ username:String, _ pw:String) -> Void) -> UIAlertController { let alert = UIAlertController(title: "Login", message: "", preferredStyle: .alert) // 1. 单独创建登录按钮并初始化为禁用状态 let loginAction = UIAlertAction(title: "Log in", style: .default, handler: { _ in guard let username = alert.textFields?[0].text, let password = alert.textFields?[1].text else { return } buttonPressed(username, password) }) loginAction.isEnabled = false alert.addAction(loginAction) // 2. 添加用户名输入框并绑定监听 alert.addTextField { textField in textField.placeholder = "Enter Username" textField.addTarget(nil, action: #selector(checkInputValidity), for: .editingChanged) // 通过userInfo传递alert和按钮实例,方便监听方法调用 textField.userInfo = ["alert": alert, "action": loginAction] } // 3. 添加密码输入框并绑定监听 alert.addTextField { textField in textField.placeholder = "Enter Password" textField.isSecureTextEntry = true textField.addTarget(nil, action: #selector(checkInputValidity), for: .editingChanged) textField.userInfo = ["alert": alert, "action": loginAction] } return alert } // 4. 静态类的@objc方法,用于实时校验输入有效性 @objc private static func checkInputValidity(_ sender: UITextField) { guard let alert = sender.userInfo?["alert"] as? UIAlertController, let loginAction = sender.userInfo?["action"] as? UIAlertAction, let usernameField = alert.textFields?[0], let passwordField = alert.textFields?[1] else { return } // 过滤空白字符后检查输入是否非空 let validUsername = !usernameField.text!.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty let validPassword = !passwordField.text!.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty // 根据校验结果更新按钮状态 loginAction.isEnabled = validUsername && validPassword }
修改说明
- 将登录按钮单独实例化并初始禁用,便于后续动态修改状态
- 给输入框添加
editingChanged事件监听,通过userInfo传递alert和按钮实例,解决静态类无法直接捕获外部变量的问题 - 实现
checkInputValidity静态方法(标记@objc),实时校验两个输入框内容,满足条件时启用登录按钮 - 增加密码框的
isSecureTextEntry属性,符合登录场景的常规需求 - 校验时过滤空白字符,避免用户输入空格误触发按钮启用
调用代码无需修改
原UIViewController中的调用代码保持不变,弹窗会自动根据输入状态控制按钮可用性。
内容的提问来源于stack exchange,提问作者Neph
相关产品推荐
相关产品推荐

