wotzup wotzup - 11 months ago 56
iOS Question

How to dismiss keyboard with multiple UITextField

I'm a noob here and in iOS world. I am having trouble dismiss keyboard on a specific case in my very simple todo list iOS app.

I'd like the keyboard to get dismiss when user taps anywhere outside the current text field or the keyboard itself. So far, I got the keyboard dismisses just fine (thanks to you guys here in stack overflow) when user taps on the UITableView, or most element on my app. HOWEVER, when user taps on another UITextField, the keyboard does not go away.

FYI, here's the list of existing threads I researched so far but have yet to solve this issue.
1) How to dismiss keyboard iOS programmatically
2) Resigning First Responder for multiple UITextFields
3) Dismissing the First Responder/Keyboard with multiple Textfields
4) (a few more at least but I lost track :( )

Here's what I did so far:

(in viewDidLoad())
// Add 'tap' gesture to dismiss keyboard when done adding/editing to-do item
var tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "tapOutside:")
tap.cancelsTouchesInView = true

func tapOutside(tapOutside: UIGestureRecognizer) {
// Dismiss keyboard

@IBAction func EditingDidBegin(sender: UITextField) {
// Highlight the text field which user is editing
self.highlightTextField(sender, highlight: true)

@IBAction func EditingDidEnd(sender: UITextField) {
// Undo text field highlight
self.highlightTextField(sender, highlight: false)

self.view.endEditing(true) // try this option and not working
self.setEditing(false, animated: true) // try this option and not working
sender.resignFirstResponder() // try this option and not working
UIApplication.sharedApplication().becomeFirstResponder() // try this option and not working

... // below is my code to update the todo item

I also tried to print out all subviews.isFirstResponder() of my view. All of it return false. I also tried override touchesBegan of my UIViewController, and inside it just calls self.view.endEditing(true) and call its super's. This also does not work.

Please help. :(


You guys are awesome! :D I got it working now thanks to you guys. There were several mistakes / messed up as I'm learning new framework. So here's what I did.

1) I did not set UITextField delegate correctly.
Mistake: I ctrl-draged textfield in xcode and link my viewController as delegate and thought that should work out. I will still need to research and understand better why.
Solution: I removed that ctrl-drag link and explicitly call myTextField.delegate = self in tableView:cellForRowAtIndexPath. And that did it. Thanks @Sidewalker

2) Mistake: I have a mixed of textFieldShouldBeginEditing, etc. and @IBAction func EditingDidBegin. So I got myself into the situation where textFieldShouldBeginEditing got the call, but EditingDidBegin did not get call.
Solution: Once I set the delegate = self explicitly and stick with implementing textField... methods and not use any @IBAction for textField, things just work.

Answer Source

Here's one option... We're going to add a boolean flag to determine whether or not we're in a textField when an edit attempt for another textField begins

Make your class adhere to UITextFieldDelegate

class MyClass: UIViewController, UITextFieldDelegate

Don't forget to set the delegate, we'll add the flag as well

myTextField.delegate = self
var inField = false

Implement "textFieldShouldBeginEditing" and "textFieldDidBeginEditing"

func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
    if inField {
        inField = false
        return false

func textFieldDidBeginEditing(textField: UITextField) {
    inField = true

I prefer tracking things like this rather than identifying subviews as it allows the flag to be utilized elsewhere and cuts down code complexity.