【问题标题】:Enable a button in Swift only if all text fields have been filled out仅当所有文本字段都已填写时才在 Swift 中启用按钮
【发布时间】:2016-01-22 07:17:44
【问题描述】:

我无法弄清楚如何更改我的代码,以便在填写我的三个文本字段时启用导航栏中的“完成”按钮。

我目前有三个 UITextField 和一个 UIButtonItem。 habitNameField 和goalField 都是手动文本字段,frequencyField 是Picker View。

@IBOutlet weak var habitNameField: UITextField!
@IBOutlet weak var goalField: UITextField!
@IBOutlet weak var frequencyField: UITextField!

@IBOutlet weak var doneBarButton: UIBarButtonItem!

当在第一个字段中输入内容时,我还有以下功能。

func textField(habitNameField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    let oldHabitNameText: NSString = habitNameField.text!
    let newHabitNameText: NSString = oldHabitNameText.stringByReplacingCharactersInRange(range, withString: string)
    doneBarButton.enabled = (newHabitNameText.length != 0)
    return true
}

我尝试更改代码,使其将其他两个字段作为参数,并仅在填写所有三个字段时才启用 doneBarButton。

func textField(habitNameField: UITextField, goalField: UITextField, frequencyField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    let habitNameText: NSString = (habitNameField.text!).stringByReplacingCharactersInRange(range, withString: string)
    let goalText: NSString = (goalField.text!).stringByReplacingCharactersInRange(range, withString: string)
    let frequencyText: NSString = (frequencyField.text!).stringByReplacingCharactersInRange(range, withString: string)

    doneBarButton.enabled = (habitNameText.length != 0) && (goalText.length != 0) && (frequencyText.length != 0)
    return true
}

但是,即使我填写了所有三个文本字段,它也不起作用。

我非常感谢任何帮助,并感谢任何提前做出贡献的人!

这里的所有代码:

class HabitDetailViewController: UITableViewController, UITextFieldDelegate, UIPickerViewDataSource,UIPickerViewDelegate {
@IBOutlet weak var habitNameField: UITextField!
@IBOutlet weak var goalField: UITextField!
@IBOutlet weak var doneBarButton: UIBarButtonItem!
@IBOutlet weak var frequencyField: UITextField!

var frequencies = ["Day", "Week", "Month", "Year"]
var frequencyPicker = UIPickerView()

var habitToEdit: HabitItem?
weak var delegate: HabitDetailViewControllerDelegate?

@IBAction func cancel() {
    delegate?.habitDetailViewControllerDidCancel(self)
}

@IBAction func done() {
    print("You plan to do \(habitNameField.text!) \(goalField.text!) times a \(frequencyField.text!.lowercaseString).")
    if let habit = habitToEdit {
        habit.name = habitNameField.text!
        habit.numberLeft = Int(goalField.text!)!
        habit.frequency = frequencyField.text!
        delegate?.habitDetailViewController(self, didFinishEditingHabit: habit)
    } else {
        let habit = HabitItem()
        habit.name = habitNameField.text!
        habit.numberLeft = Int(goalField.text!)!
        habit.frequency = frequencyField.text!
        habit.completed = false
        delegate?.habitDetailViewController(self, didFinishAddingHabit: habit)
    }
}

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    habitNameField.becomeFirstResponder()
    frequencyPicker.hidden = false
}

override func viewDidLoad() {
    super.viewDidLoad()
    frequencyPicker.dataSource = self
    frequencyPicker.delegate = self
    doneBarButton.enabled = false
    habitNameField.addTarget(self, action: "checkFields:", forControlEvents: .EditingChanged)
    goalField.addTarget(self, action: "checkFields:", forControlEvents: .EditingChanged)
    frequencyField.addTarget(self, action: "checkFields:", forControlEvents: .EditingChanged)
    frequencyField.inputView = frequencyPicker
    if let habit = habitToEdit {
        title = "Edit Item"
        habitNameField.text = habit.name
        goalField.text = String(habit.numberLeft)
        doneBarButton.enabled = true
    }
}

override func tableView(tableView: UITableView, willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath? {
    return nil
}

func textField(habitNameField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    let oldHabitNameText: NSString = habitNameField.text!
    let newHabitNameText: NSString = oldHabitNameText.stringByReplacingCharactersInRange(range, withString: string)
    doneBarButton.enabled = (newHabitNameText.length != 0)
    return true
}

func checkFields(sender: UITextField) {
    sender.text = sender.text?.stringByTrimmingCharactersInSet(.whitespaceCharacterSet())
    guard
        let habit = habitNameField.text where !habit.isEmpty,
        let goal = goalField.text where !goal.isEmpty,
        let frequency = frequencyField.text where !frequency.isEmpty
        else { return }
    // enable your button if all conditions are met
    doneBarButton.enabled = true
}

【问题讨论】:

    标签: ios iphone swift uitextfield swift2


    【解决方案1】:

    Xcode 9 • Swift 4

    您可以 addTarget 到您的文本字段以监视控制事件 .editingChanged 并为所有这些事件使用单个选择器方法:

    override func viewDidLoad() {
        super.viewDidLoad()
        doneBarButton.isEnabled = false
        [habitNameField, goalField, frequencyField].forEach({ $0.addTarget(self, action: #selector(editingChanged), for: .editingChanged) })
    }
    

    创建选择器方法并使用guard 结合where 子句(Swift 3/4 使用逗号)确保所有文本字段不为空,否则直接返回。 Swift 3 不需要@objc,但 Swift 4 需要:

    @objc func editingChanged(_ textField: UITextField) {
        if textField.text?.characters.count == 1 {
            if textField.text?.characters.first == " " {
                textField.text = ""
                return
            }
        }
        guard
            let habit = habitNameField.text, !habit.isEmpty,
            let goal = goalField.text, !goal.isEmpty,
            let frequency = frequencyField.text, !frequency.isEmpty
        else {
            doneBarButton.isEnabled = false
            return
        }
        doneBarButton.isEnabled = true
    }
    

    sample

    【讨论】:

    • 这是有效的,但出于某种原因,即使只填写了部分字段,它也有效。这是为什么呢?
    • 杜尔。这是我的菜鸟错误。谢谢你帮我抓住了。此外,频率的最终文本字段不起作用,因为它是一个选择器视图。有什么想法吗?
    • 您可以创建一个布尔变量来监控它,并在用户设置它后对其进行标记。然后只需将其添加到保护语句中
    • 如何检查电子邮件 id 并且单个文本字段不为空,尝试过但不工作 let emaiTextField = existingEmailAddressTextField.text, !emaiTextField.isEmpty, let validEmail = existingEmailAddressTextField.text, self.validateEmail(validEmail) ==真,
    • 如何检查相同文本字段的有效电子邮件 ID
    【解决方案2】:

    Swift 5.1 /Xcode 11

    override func viewDidLoad() {
        super.viewDidLoad()
        setupAddTargetIsNotEmptyTextFields()        
    }
    
    func setupAddTargetIsNotEmptyTextFields() {
        okButton.isHidden = true //hidden okButton
        nameUserTextField.addTarget(self, action: #selector(textFieldsIsNotEmpty), 
                                    for: .editingChanged)
        emailUserTextField.addTarget(self, action: #selector(textFieldsIsNotEmpty), 
                                    for: .editingChanged)
        passwordUserTextField.addTarget(self, action: #selector(textFieldsIsNotEmpty), 
                                    for: .editingChanged)
        confimPasswordUserTextField.addTarget(self, action: #selector(textFieldsIsNotEmpty), 
                                    for: .editingChanged)        
       }
    

    然后创建选择器方法并使用guard:

    @objc func textFieldsIsNotEmpty(sender: UITextField) {
    
        sender.text = sender.text?.trimmingCharacters(in: .whitespaces)
    
        guard
          let name = nameUserTextField.text, !name.isEmpty,
          let email = emailUserTextField.text, !email.isEmpty,
          let password = passwordUserTextField.text, !password.isEmpty,
          let confirmPassword = confimPasswordUserTextField.text,
              password == confirmPassword          
          else
        {
          self.okButton.isHidden = true
          return
        }
        // enable okButton if all conditions are met
        okButton.isHidden = false
       }
    

    【讨论】:

    • 应该是正确的答案,对我来说效果很好,委托方法不提供类似 .editingChanged 的​​东西
    • 很好的解决方案!您需要将“textFieldsIsNotEmpty”标记为“@objc”,否则编译器会抛出错误。请更新答案。
    • 如何检查是否有效的电子邮件 ID 并为相同的文本字段留空
    【解决方案3】:

    最好的方法是在 ViewDidLoad 方法中添加观察者。不仅仅是检查 textField Delegate 方法是否所有 TextField 都已填满。一旦它填满调用 oberserver 方法,您只需要启用按钮。

    注意:

    • 您可以将观察者用于启用或禁用按钮

    希望对你有所帮助。

    【讨论】:

    • 你能举例说明如何添加观察者吗?谢谢!
    【解决方案4】:

    我继续将其抽象为一个帮助类,可以用于他们的 swift 项目。

    import Foundation
    import UIKit
    
    class ButtonValidationHelper {
    
      var textFields: [UITextField]!
      var buttons: [UIButton]!
    
      init(textFields: [UITextField], buttons: [UIButton]) {
    
        self.textFields = textFields
        self.buttons = buttons
    
        attachTargetsToTextFields()
        disableButtons()
        checkForEmptyFields()
      }
    
      //Attach editing changed listeners to all textfields passed in
      private func attachTargetsToTextFields() {
        for textfield in textFields{
            textfield.addTarget(self, action: #selector(textFieldsIsNotEmpty), for: .editingChanged)
        }
      }
    
      @objc private func textFieldsIsNotEmpty(sender: UITextField) {
        sender.text = sender.text?.trimmingCharacters(in: .whitespaces)
        checkForEmptyFields()
      }
    
    
      //Returns true if the field is empty, false if it not
      private func checkForEmptyFields() {
    
        for textField in textFields{
            guard let textFieldVar = textField.text, !textFieldVar.isEmpty else {
                disableButtons()
                return
            }
        }
        enableButtons()
      }
    
      private func enableButtons() {
        for button in buttons{
            button.isEnabled = true
        }
      }
    
      private func disableButtons() {
        for button in buttons{
            button.isEnabled = false
        }
      }
    
    }
    

    然后在您的视图控制器中只需简单地使用

    初始化助手
    buttonHelper = ButtonValidationHelper(textFields: [textfield1, textfield2, textfield3, textfield4], buttons: [button])
    

    确保在顶部保留一个强引用以防止释放

    var buttonHelper: ButtonValidationHelper!
    

    【讨论】:

      【解决方案5】:
      func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
          if (textField == self.textField1) { /* do Something */ }
          else if (textField == self.textField2) { /* do Something */ }
          else if (textField == self.textField3) { /* do Something */ }
      
          // regardless of what you do before, doneBarButton is enabled when all are not empty
          doneBarButton.enabled = (textField1.length != 0) && (textField2.length != 0) && (textField3.length != 0)
          return true
      

      }

      【讨论】:

        【解决方案6】:

        为什么不将检查功能移到单独的函数中

        func setDoneButtonStatus()
        {
            let habitNameText: NSString = (habitNameField.text!).stringByReplacingCharactersInRange(range, withString: string)
            let goalText: NSString = (goalField.text!).stringByReplacingCharactersInRange(range, withString: string)
            let frequencyText: NSString = (frequencyField.text!).stringByReplacingCharactersInRange(range, withString: string)
        
            doneBarButton.enabled = (habitNameText.length != 0) && (goalText.length != 0) && (frequencyText.length != 0)
        }
        

        然后使用

        func textFieldShouldReturn(textField: UITextField) -> Bool
        {
            textField.resignFirstResponder()
            setDoneButtonStatus()
        }
        

        【讨论】:

          【解决方案7】:

          这对我有用:希望它有所帮助

            func textFieldDidEndEditing(textField: UITextField) {
                  if txtField1.hasText() && textField2.hasText() && textField3.hasText(){
                      doneBarButton.enabled = true
                  }
              }
          

          【讨论】:

          • 请注意,这仅适用于 iOS(10.0 及更高版本)、tvOS(10.0 及更高版本)。顺便说一句,它不再是一种方法。现在它是一个计算属性
          【解决方案8】:

          您可以创建文本字段数组[UITextField] 或插座集合。让我们将数组称为 textFields 或类似的名称。

          doneBarButton.isEnabled = !textFields.flatMap { $0.text?.isEmpty }.contains(true)
          

          并在监控文本字段文本变化的方法中调用上面的代码。

          【讨论】:

            【解决方案9】:

            使用 Combine (Xcode11+, iOS13+) 这变得更容易了。

            首先,您需要能够为文本更改创建发布者:

            extension UITextField {
            
                var textPublisher: AnyPublisher<String, Never> {
                    NotificationCenter.default
                        .publisher(for: UITextField.textDidChangeNotification, object: self)
                        .compactMap { $0.object as? UITextField }
                        .map { $0.text ?? "" }
                        .eraseToAnyPublisher()
                }
            
            }
            

            然后你可以组合来自多个文本字段的多个发布者:

            private var readyToLogIn: AnyPublisher<Bool, Never> {
               return Publishers
                  .CombineLatest(
                     emailTextField.textPublisher, passwordTextField.textPublisher
                  )
                  .map { email, password in
                     !email.isEmpty && !password.isEmpty
                  }
                  .eraseToAnyPublisher()
            }
            
            

            然后根据组合的 Publisher 更改按钮的 isEnabled 属性

            readyToLogIn
               .receive(on: RunLoop.main)
               .assign(to: \.isEnabled, on: signInButton)
            

            【讨论】:

              【解决方案10】:

              Swift 5.0+

              我会做这样的事情,它结合了已经给出的答案,但更加精简和最新:

              在你的viewDidLoad()

                  [usernameTextField, passwordTextField].forEach {
                      $0?.addTarget(self,
                                    action: #selector(editingChanged(_:)),
                                    for: .editingChanged)
                  }
              

              然后创建以下内容:

              @objc func editingChanged(_ textField: UITextField) {
                  
                  // Trim whitespace and newlines
                  textField.text = textField.text?.trimmingCharacters(in: .whitespacesAndNewlines)
                  
                  // Assumes loginButton exists and there's a reference to it in the current scope.
                  loginButton.isEnabled = ![usernameTextField, passwordTextField].compactMap {
                      $0.text?.isEmpty
                  }.contains(true)
              }
              

              【讨论】:

                【解决方案11】:

                Xcode 10.2 • Swift 4.3 版本的 Leo Dabus 以上。

                此解决方案用于添加用户,可能是最常见的实现 进行此类验证。

                override func viewDidLoad() {
                super.viewDidLoad()
                addUserButton.backgroundColor = disabledButtonColor
                addUserButton.isEnabled = false
                
                [emailField, userNameField, firstNameField, lastNameField].forEach { (field) in
                    field?.addTarget(self,
                                     action: #selector(editingChanged(_:)),
                                     for: .editingChanged)
                }}
                
                
                
                @objc private func editingChanged(_ textField: UITextField) {
                if textField.text?.count == 1 {
                    if textField.text?.first == " " {
                        textField.text = ""
                        return
                    }
                }
                guard
                    let email       = emailField.text,      !email.isEmpty,
                    let userName    = userNameField.text,   !userName.isEmpty,
                    let firstName   = firstNameField.text,  !firstName.isEmpty,
                    let lastName    = lastNameField.text,   !lastName.isEmpty
                    else {
                        addUserButton.isEnabled = false
                        addUserButton.backgroundColor = disabledButtonColor
                        return
                }
                addUserButton.isEnabled = true
                addUserButton.backgroundColor = activeButtonColor
                

                }

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2017-10-25
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2021-07-23
                  • 1970-01-01
                  相关资源
                  最近更新 更多