我无法弄清楚如何更改我的代码,以便在填写完三个文本字段时启用导航栏中的“完成”按钮。
我目前有三个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
}
答案 0 :(得分:34)
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
}
答案 1 :(得分:7)
Swift 3 / Xcode 8.2
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)
}
然后创建选择器方法并使用后卫:
@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
}
P.S。在swift 3“其中”==&gt;&gt;&gt; “<强>,强>”
答案 2 :(得分:3)
最好的方法是在ViewDidLoad方法中添加观察者。而不仅仅是检查textField Delegate方法是否所有TextField都被填满。一旦填满了电话oberserver方法&amp;因为你只需要启用按钮。
注意:强>
希望它会对你有所帮助。
答案 3 :(得分:1)
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
}
答案 4 :(得分:1)
为什么不将检查功能移到单独的功能
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()
}
答案 5 :(得分:1)
这对我有用:希望有所帮助
func textFieldDidEndEditing(textField: UITextField) {
if txtField1.hasText() && textField2.hasText() && textField3.hasText(){
doneBarButton.enabled = true
}
}
答案 6 :(得分:1)
我继续将这一点抽象出一个可以用于快速项目的辅助类。
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
}
}
}
然后在您的View Controller中只需使用
初始化帮助程序buttonHelper = ButtonValidationHelper(textFields: [textfield1, textfield2, textfield3, textfield4], buttons: [button])
确保在顶部保留强大的引用以防止重新分配
var buttonHelper: ButtonValidationHelper!
答案 7 :(得分:0)
您可以创建文本字段[UITextField]
或插座集合的数组。让我们调用数组textFields
或类似的东西。
doneBarButton.isEnabled = !textFields.flatMap { $0.text?.isEmpty }.contains(true)
并在监视文本字段文本更改的方法中调用上面的代码。
答案 8 :(得分:0)
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
}
答案 9 :(得分:0)
有了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 :(得分:0)
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)
}