web-dev-qa-db-ja.com

Swiftのボタンを有効にします。すべてのテキストフィールドが入力されている場合のみ

コードを変更して、3つのテキストフィールドに入力したときにナビゲーションバーの[完了]ボタンが有効になるようにコードを変更する方法がわかりません。

現在、3つのUITextFieldと1つの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
}

コードを変更して、他の2つのフィールドをパラメーターとして受け取り、3つのフィールドがすべて入力された場合にのみ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
}

ただし、3つのテキストフィールドすべてに入力しても動作しません。

私はどんな助けも本当に感謝します、そして事前に貢献してくれた人に感謝します!

すべてのコードはこちら:

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
}
14
Derek Mei

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
}

サンプル

41
Leo Dabus

Swift 3/Xcode 8.2

enter image description here

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

次にselectorメソッドを作成し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
   }

追伸In Swift 3 "where" == >>> "

8
A.Kant

最善の方法は、ViewDidLoadメソッドにオブザーバーを追加することです。すべてのTextFieldがいっぱいになっているかどうかをtextField Delegateメソッドでチェックインするだけではありません。いっぱいになったらoberserverメソッドを呼び出して、ボタンを有効にするだけです。

注:

  • ボタンを有効または無効にするためにオブザーバーを使用できます

それがあなたを助けることを願っています。

3
Mayur

私は先に進み、これをビット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
    }
  }

}

そして、View Controllerでヘルパーを単にinitするだけです

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

割り当て解除を防ぐために、必ず最上位に強力な参照を保持してください

var buttonHelper: ButtonValidationHelper!
2
Stus

チェック機能を別の機能に移行しないのはなぜですか

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

これは私のために働く:それが役立つことを願って

  func textFieldDidEndEditing(textField: UITextField) {
        if txtField1.hasText() && textField2.hasText() && textField3.hasText(){
            doneBarButton.enabled = true
        }
    }
1
Alakh
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

}

1
Ramy Kfoury

テキストフィールドの配列を作成できます[UITextField]またはアウトレットコレクション。配列textFieldsまたはそのようなものを呼び出しましょう。

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

また、テキストフィールドのテキストの変更を監視するメソッドで上記のコードを呼び出します。

0
xcocoader

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

}

0
user550088