Ios 仅当所有文本字段均已填写时,才启用Swift中的按钮

Ios 仅当所有文本字段均已填写时,才启用Swift中的按钮,ios,iphone,swift,uitextfield,swift2,Ios,Iphone,Swift,Uitextfield,Swift2,我很难弄清楚如何更改我的代码,使之成为在填写三个文本字段时启用导航栏中的“完成”按钮 我目前有三个UITextFields和一个UIButtonItem。habitNameField和goalField都是手动文本字段,frequencyField是选择器视图 @IBOutlet weak var habitNameField: UITextField! @IBOutlet weak var goalField: UITextField! @IBOutlet weak var frequency

我很难弄清楚如何更改我的代码,使之成为在填写三个文本字段时启用导航栏中的“完成”按钮

我目前有三个UITextFields和一个UIButtonItem。habitNameField和goalField都是手动文本字段,frequencyField是选择器视图

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

}

为什么不将检查功能移动到单独的功能

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

最好的方法是在ViewDidLoad方法中添加观察者。而不仅仅是在textField委托方法中检查所有textField是否已填充。一旦它被填满,就调用oberserver方法&在这种情况下,您只需要启用按钮

注意:

  • 您可以对“启用”或“禁用”按钮使用“观察者”

希望它能帮助您。

Xcode 9•Swift 4

您可以将目标添加到文本字段中,以监视控件事件。编辑已更改,并对所有控件使用单个选择器方法:

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
}

这对我很有效:希望能有所帮助

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

Swift 5.1/Xcode 11

然后创建选择器方法并使用保护

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

我继续将其抽象为一个助手类,可以用于他们的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!

您可以创建文本字段数组
[UITextField]
或outlet集合。让我们调用数组
textFields
或类似的东西

doneBarButton.isEnabled = !textFields.flatMap { $0.text?.isEmpty }.contains(true)
并在监视文本字段的文本更改的方法中调用上面的代码

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

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

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
}

使用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()
    }

}

Swift 5.0+

我会这样做,这是已经给出的答案的组合,但更加精简和更新:

在您的
viewDidLoad()中

然后创建以下内容:

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

这是可行的,但出于某种原因,即使只填写了其中一个字段,它也可以工作。为什么?杜尔。这是我的新手错误。谢谢你帮我接电话。此外,frequency的最终文本字段不起作用,因为它是一个选择器视图。有什么想法吗?您可以创建一个布尔变量来监视它,并在用户设置它后对其进行标记。然后只需将其添加到guard语句如何检查单个文本字段的电子邮件id且不为空,尝试此操作但不起作用让emaiTextField=existingEmailAddressTextField.text!emaiTextField.isEmpty,让validEmail=existingEmailAddressTextField.text,self.validateEmail(validEmail)==true,如何检查同一文本字段的有效电子邮件id应该是正确的答案,对我来说效果很好,委托方法不提供类似.editingChangedGreat的解决方案!您需要将“textFieldsIsNotEmpty”标记为“@objc”,否则编译器会抛出错误。请更新答案。如何检查是否有效的电子邮件id以及同一文本字段是否为空请注意,这仅适用于iOS(10.0及更高版本)、tvOS(10.0及更高版本)。顺便说一句,它不再是一种方法。现在它是一个计算属性。你能举个例子说明如何添加观察者吗?谢谢!
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()
}

readyToLogIn
   .receive(on: RunLoop.main)
   .assign(to: \.isEnabled, on: signInButton)
    [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)
}