1

I have a simple UITableViewController with 6 rows, each with a UITextField. I want to be able to click on each row and have the keyboard apply to each. Everything works, except for some reason I have to click on each row twice to get the responder to make the next UITextField active. I put in UITextFieldDelegate printouts and the order of their actions seems wrong. Each of the TextFields has been tagged 0 - 5. When I select the first, there is no problem, the keyboard comes up, I enter something. My printout is:

textFieldShouldBeginEditing tag: 0 textFieldDidBeginEditing tag: 0

Then I select the next row (without hitting Done in the keyboard) and the printout is this:

textFieldShouldBeginEditing tag: 1 textFieldShouldEndEditing tag: 0 textFieldDidEndEditing tag: 0

Why is textFieldDidBeginEditing not being called?

Here is my code in case it helps:

class EstimateCell: UITableViewCell, UITextFieldDelegate {


  @IBOutlet weak var estimateField: UITextField!

  // callback to alert when user clicked "Done"
  var doneTextFieldInput: ((cell: EstimateCell, newText:String?) -> Void)?


  override func awakeFromNib() {
    super.awakeFromNib()
    // Initialization code

   // self.selectionStyle = .None

    estimateField.delegate = self
    estimateField.clearsOnBeginEditing = true

    // add a done button to the numberpad
    addDoneButtonOnNumpad(estimateField)

    // add some padding to the right margin
    estimateField.layer.sublayerTransform = CATransform3DMakeTranslation(-20, 0, 0)
  }

  override func setSelected(selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)

    // Configure the view for the selected state
  }

  /**
   Only allow 4 digits
   */
  func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {

    // only allow 4 digits max
    guard let text = textField.text else { return true }
    let newLength = text.characters.count + string.characters.count - range.length
    let isMax4digits = newLength <= 5
    return isMax4digits
  }

  func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
    print("textFieldShouldBeginEditing \(textField.tag)")

    return true
  }
  func textFieldDidBeginEditing(textField: UITextField) {
    textField.text = ""
    print("textFieldDidBeginEditing \(textField.tag)")
  }

  func textFieldShouldEndEditing(textField: UITextField) -> Bool {
    print("textFieldShouldEndEditing \(textField.tag)")
    return true
  }

  /**
   Called after the textfield resigns as the first responder
   */
  func textFieldDidEndEditing(textField: UITextField) {
    print("textFieldDidEndEditing \(textField.tag)")
    doneTextFieldInput?(cell: self, newText: textField.text)
   // textField.resignFirstResponder()
  }

  func textFieldShouldReturn(textField: UITextField) -> Bool {
    print("textFieldShouldReturn")
    textField.resignFirstResponder()
    return true
  }
  /**
   Adds a toolbar with a Done button as an input accessory view to the given textfield.  Calls
   resignFirstResponder when Done is clicked.
   */
  func addDoneButtonOnNumpad(textField: UITextField)
  {
    let keypadToolbar: UIToolbar = UIToolbar()

    // add a done button to the numberpad
    keypadToolbar.items=[
      UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.Done, target: textField, action: #selector(UITextField.resignFirstResponder)),
      UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: self, action: nil)
    ]
    keypadToolbar.sizeToFit()
    // add a toolbar with a done button above the number pad
    textField.inputAccessoryView = keypadToolbar
  }
}
Coder1224
  • 1,785
  • 2
  • 17
  • 21
  • try with removing below code from awakeFromNib() method estimateField.clearsOnBeginEditing = true – Harish Singh Jan 04 '17 at 07:31
  • Unfortunately that didn't do it. Thanks for the try though! My only other thought is change to a UIViewController and put a UITableView inside and try like that. The reason I didn't do that to begin with is to get the auto scroll feature when selecting one of the lower textfields. – Coder1224 Jan 04 '17 at 07:44
  • Thanks for quick review and good luck @Coder1224 – Harish Singh Jan 04 '17 at 07:50

1 Answers1

5

I figured it out. The problem is I was calling tableView.reloadData() in my callback inside textFieldDidEndEditing(). This caused the code that sets my textfield.delegate = self to fire again, which was being done before textFieldShouldBeginEditing() could be called. Hopefully this helps someone else out there one day: don't reload your tableview from inside textFieldDidEndEditing().

Coder1224
  • 1,785
  • 2
  • 17
  • 21