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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 19:05:32