2016-01-22 33 views
8

Tôi đang gặp khó khăn khi tìm cách thay đổi mã của mình để làm cho nút sao cho nút Xong trong thanh điều hướng được bật khi ba trường văn bản của tôi được điền.Bật nút trong Swift chỉ khi tất cả các trường văn bản đã được điền

Tôi hiện có ba UITextField và một UIButtonItem. Cả hai đối tượng habitNameField và goalField đều là các trường văn bản thủ công và frequencyField là một khung nhìn Picker View.

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

@IBOutlet weak var doneBarButton: UIBarButtonItem! 

Tôi cũng có chức năng sau hoạt động khi có nội dung nào đó được nhập trong trường đầu tiên.

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 
} 

Tôi đã thử thay đổi mã để lấy trong hai trường khác làm tham số và chỉ bật doneBarButton nếu cả ba trường được điền.

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 
} 

Tuy nhiên, nó không hoạt động, ngay cả khi tôi điền vào cả ba trường văn bản.

Tôi thực sự đánh giá cao bất kỳ trợ giúp nào và nhờ bất kỳ ai đóng góp trước!

Tất cả các mã ở đây:

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 
} 

Trả lời

18

Xcode 8.3.2 • Swift 3.1

Bạn có thể addTarget đến lĩnh vực văn bản để giám sát cho sự kiện điều khiển .editingChanged và sử dụng một phương pháp chọn duy nhất cho tất cả trong số họ:

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

Tạo phương pháp chọn và sử dụng guard kết hợp với where khoản (Swift 3 sử dụng dấu phẩy) để đảm bảo tất cả các lĩnh vực văn bản không có sản phẩm nào khác chỉ trả:

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 
} 

sample

+0

Điều này đang hoạt động, nhưng vì một số lý do, nó hoạt động ngay cả khi chỉ có các trường được điền. Tại sao lại như vậy? –

+0

Durr. Đó là một sai lầm tân binh về phía tôi. Cảm ơn vì đã giúp tôi nắm bắt điều đó. Ngoài ra, trường văn bản cuối cùng cho tần suất không hoạt động vì đó là chế độ xem bộ chọn. Bất kỳ ý tưởng về điều đó? –

+0

Bạn có thể tạo một biến boolean để theo dõi nó và gắn cờ nó khi người dùng thiết lập nó. Sau đó, chỉ cần thêm nó vào tuyên bố bảo vệ –

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 

}

1

tại sao không di chuyển các chức năng kiểm tra đến một chức năng riêng biệt

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

và sau đó sử dụng

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

Cách tốt nhất là Thêm người quan sát vào phương pháp ViewDidLoad. Hơn chỉ cần kiểm tra trong textField Delegate phương pháp cho dù tất cả TextFields được lấp đầy hay không. Khi phương thức oberserver gọi đầy của nó là &, bạn chỉ cần kích hoạt nút.

Lưu ý:

  • Bạn có thể sử dụng quan sát cho cả kích hoạt hoặc vô hiệu hóa nút

Hy vọng nó sẽ giúp bạn.

1

này làm việc cho tôi: Hy vọng nó giúp

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

Lưu ý rằng tính năng này chỉ khả dụng cho iOS (10.0 trở lên), tvOS (10.0 trở lên). BTW nó không phải là một phương pháp nữa. Bây giờ nó là một tài sản tính toán –

6

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

và sau đó tạo ra các phương pháp selector và sử dụng bảo vệ:

@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. Trong nhanh chóng 3 "nơi" == >>> ","

+0

Nên là câu trả lời đúng, nó hoạt động tốt cho tôi, phương pháp đại biểu không cung cấp một cái gì đó như .editingChanged – Bradley

+0

Giải pháp tuyệt vời! Bạn cần đánh dấu 'textFieldsIsNotEmpty' là '@objc' nếu trình biên dịch gửi lỗi. Vui lòng cập nhật câu trả lời. – Prabhav

+0

Xin chào, @Prabhav. Sẵn sàng, cảm ơn –

1

tôi đã đi trước và trừu tượng này ra một chút vào một lớp helper mà người ta có thể sử dụng cho dự án nhanh chóng của họ.

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

} 

Và sau đó trong View Controller của bạn chỉ đơn giản là init helper với

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

Hãy chắc chắn rằng bạn giữ một tham chiếu mạnh mẽ ở phía trên để ngăn chặn deallocation

var buttonHelper: ButtonValidationHelper! 
0

Bạn có thể tạo một mảng của các trường văn bản [UITextField] hoặc bộ sưu tập đầu ra. Hãy gọi mảng textFields hoặc một cái gì đó tương tự.

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

Và gọi mã ở trên theo phương pháp theo dõi thay đổi văn bản của trường văn bản.

Các vấn đề liên quan