1

I have set up a gesture recognizer for dismissing the keyboard when the user taps outside the textfield. DismissKeyboard function does not get called.

Have I set up the observer wrong or is this a different issue? Also, this is a tableview that is being tapped.

Code Excerpt

class CommentsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        NSNotificationCenter.defaultCenter().addObserver(self,
            selector: Selector("keyboardWillShow:"),
            name: UIKeyboardWillShowNotification,
            object: nil)
        NSNotificationCenter.defaultCenter().addObserver(self,
            selector: Selector("keyboardWillHide:"),
            name: UIKeyboardWillHideNotification,
            object: nil)
    }

    func keyboardFrameChanged(notification: NSNotification) {
        println("keyboardFrameChanged")
        let userInfo = notification.userInfo
        let key = UIKeyboardFrameEndUserInfoKey
        if let info = userInfo {
            let frameValue = info[key] as! NSValue
            let _frame = frameValue.CGRectValue()
        }
    }
    
    func keyboardWillShow(notification: NSNotification) {
        if keyboardDismissTapGesture == nil
        {
            println("dismiss")
            keyboardDismissTapGesture = UITapGestureRecognizer(target: self, action: Selector("dismissKeyboard:"))
            self.view.addGestureRecognizer(keyboardDismissTapGesture!)
        }
    }
    
    func keyboardWillHide(notification: NSNotification) {
        if keyboardDismissTapGesture != nil
        {
            println("test2")
            self.view.removeGestureRecognizer(keyboardDismissTapGesture!)
            keyboardDismissTapGesture = nil
        }
    }
    
    func dismissKeyboard(sender: AnyObject) {
        println("dismiss keyboard")
        commentTextField.resignFirstResponder()
    }

I set a breakpoint at dismissKeyboard, but it doesn't even get called.

Output

When I tap the textview and the keyboard opens, this is the output

keyboardFrameChanged
keyboardFrameChanged
will show
dismiss

When I tap anything else (trying to dismiss the keyboard), no further outputs.

Community
  • 1
  • 1
Onichan
  • 4,476
  • 6
  • 31
  • 60

1 Answers1

2

Set the gesture recognizer delegate to yourself and add the UIGestureRecognizerDelegate protocol.

func keyboardWillShow(notification: NSNotification) {
    if keyboardDismissTapGesture == nil
    {
        println("dismiss")
        keyboardDismissTapGesture = UITapGestureRecognizer(target: view, action: "dismissKeyboard:")
        keyboardDismissTapGesture.delegate = self
        self.view.addGestureRecognizer(keyboardDismissTapGesture!)
    }
}

Then add:

func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool { 
    return true 
}

My guess is, the gesture of your table view is interfering with the new UITapGesture. Try this solution or else you should fail the gesture of your table view when your new UITapGesture is detected.

To fail the UITapGestureRecognizer of the table view I use this code:

if let recognizers = yourTableView.gestureRecognizers, let index = find(recognizers.map { $0 is UITapGestureRecognizer }, true) {
    (recognizers[index] as! UIPanGestureRecognizer).requireGestureRecognizerToFail(keyboardDismissTapGesture)
}

Maybe not the most elegant way of doing it, but it works for me when I want to fail the UIPanGestureRecognizer. I haven't tested it with the UITapGestureRecognizer.

EDIT:

if let recognizers = yourTableView.gestureRecognizers, let index = find(recognizers.map { $0 is UIGestureRecognizer }, true) {
    (recognizers[index] as! UIGestureRecognizer).requireGestureRecognizerToFail(keyboardDismissTapGesture!)
}
Eendje
  • 8,815
  • 1
  • 29
  • 31
  • Thank you! `println("dismiss keyboard")` is now being called but only when I drag + tap immediately after. Is there a reason why the gesture is not recognizing individual taps? – Onichan May 14 '15 at 22:51
  • The default for iOS is that it can only recognize one gesture at a time. I'm not that experienced yet so I can only tell you this. Something else you can do is to fail the tap gesture of the table view. I'll show you how in a sec. And if this solved your problem, please mark it as answered :p – Eendje May 14 '15 at 22:56
  • Thank you. Would you mind explaining what failing the gesture does? – Onichan May 14 '15 at 23:04
  • Lol, i mean why do I want to fail it? – Onichan May 14 '15 at 23:06
  • Sorry, I just woke up. It means, gesture1 stops working when the gesture2 is detected. This is useful like when you want to pan a view up or down and your view has a table view. Normally, if you pan vertically, you will pan your table. If this is failed, you can successfully use gesture2. – Eendje May 14 '15 at 23:10
  • If you're going to use the "fail" option, please let me know if it works. Kinda lazy to test it myself right now :p And you're welcome. – Eendje May 14 '15 at 23:13
  • I put it in `func keyboardWillShow(notification: NSNotification) {`, but nothing different happened. And `keyboardDismissTapGesture` should have `!` – Onichan May 14 '15 at 23:17
  • I've put an edit in the answer. You can try that. I hope it succeeds. If it doesn't you'll have to use the gesture delegate like in this [post](http://stackoverflow.com/questions/8192480/uitapgesturerecognizer-breaks-uitableview-didselectrowatindexpath). – Eendje May 14 '15 at 23:37
  • I added the new code. It crashes when I try to tap the textView `*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFSet addObject:]: attempt to insert nil'` – Onichan May 14 '15 at 23:44
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/77852/discussion-between-jacobson-talom-and-emma). – Eendje May 14 '15 at 23:46