Ios 仅当所有文本字段均已填写时,才启用Swift中的按钮
我很难弄清楚如何更改我的代码,使之成为在填写三个文本字段时启用导航栏中的“完成”按钮 我目前有三个UITextFields和一个UIButtonItem。habitNameField和goalField都是手动文本字段,frequencyField是选择器视图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
@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)
}