Habilite un button en Swift solo si se han completado todos los campos de text

Tengo problemas para encontrar la forma de cambiar mi código para hacerlo, por lo que el button Listo en la barra de navigation se habilita cuando mis tres campos de text se completan.

Actualmente tengo tres UITextFields y un UIButtonItem. Tanto habitNameField como goalField son campos de text manuales, y frequencyField es una vista de selección.

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

También tengo la siguiente function que funciona cuando hay algo escrito en el primer campo.

 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 } 

Intenté cambiar el código para que tomara en count los otros dos campos como parameters y habilitaba el doneBarButton solo si se habían completado los tres campos.

 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 } 

Sin embargo, no funciona, incluso cuando complete los tres campos de text.

Realmente agradecería cualquier ayuda, ¡y gracias a cualquiera que contribuya con anticipación!

Todo el código aquí:

 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 } 

Xcode 8.3.2 • Swift 3.1

Puede addTarget a los campos de text para supervisar el evento de control .editingChanged y utilizar un solo método de selección para todos ellos:

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

Cree el método del selector y use la guard combinada con la cláusula where (Swift 3 usa una coma) para asegurarse de que todos los campos de text no estén vacíos; de lo contrario, solo regrese:

 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 } 

muestra

Swift 3 / Xcode 8.2

introduzca la descripción de la imagen aquí

 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) } 

y luego cree el método selector y use guard :

 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 } 

PS en swift 3 " donde " == >>> " , "

La mejor forma sería Agregar el observador en el método ViewDidLoad. Tan solo ingrese el método textField Delegate si todos los TextFields están llenos o no. Una vez que se llene, llame al método oberserver y en eso solo necesita habilitar el button.

Nota:

  • Puede utilizar el observador para activar o desactivar el button

Espero que te ayude.

 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 

}

¿Por qué no mover la funcionalidad de comprobación a una function separada?

 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) } 

y luego usa

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

Esto funciona para mí: espero que ayude

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

Proseguí y abstraí esto un poco en una class de ayudante que se puede usar para su proyecto rápido.

 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 } } } 

Y luego, en su controller de vista, simplemente inicie el ayudante con

 buttonHelper = ButtonValidationHelper(textFields: [textfield1, textfield2, textfield3, textfield4], buttons: [button]) 

Asegúrate de mantener una fuerte reference en la parte superior para evitar la desasignación.

 var buttonHelper: ButtonValidationHelper!