2

I have a gesture recognizer that dismisses my keyboard but this gets in the way of the tableView didSelectAtRow because the tableView doesn't recognize a tap unless it is a long press. When I run this in the simulator, and tap the tableViewCell lightly, it registers as a tap to dismiss the keyboard and not as a tap to the tableView. However, if I tap and hold for a little longer in the simulator, it will both dismiss the keyboard and register as didSelectAtRow for the tableView. This is similar to question UITableView clicked and no cell selected,but long press trigger cell selected, but I do not know how to use Objective-C. I was wondering if anyone had a workaround to my issue. I was thinking if there was a way to recognize that I tapped in the tableView, that the gestureRecognizer would be cancelled, but I am not sure how to proceed.

Here is what I have so far:

override func viewDidLoad() {
    super.viewDidLoad()

    searchBar.delegate = self


    let tapGesture = UITapGestureRecognizer(target: self, action: #selector(AddressVC.hideKeyboard))
    tapGesture.cancelsTouchesInView = false
    //searchResultsTableView.addGestureRecognizer(tapGesture)
    self.view.addGestureRecognizer(tapGesture)

}
func hideKeyboard()
    {
    self.view.endEditing(true)
    }

enter image description here

Kevin
  • 1,189
  • 2
  • 17
  • 44

1 Answers1

1

Your single tap is captured by the gesture recognizer and not forwarded to the tableview. Why not use the didSelectCell function of the UITableViewDelegate to dismiss the keyboard when a cell was selected?

Otherwise you might want to implement the UIGestureRecognizerDelegate and handle the situation appropriately. Since you probably do no check if the gesture recognizers touch has started or endet, your function will get called constantly as long as you are touching.

Therefore it will fire also when you'd expect a long press only to be fired. If you want to use multiple gesture recognizers and they should not fire together, you might want to set the requires(to fail) of the other recognizer.

enter image description here

xxtesaxx
  • 6,175
  • 2
  • 31
  • 50
  • I am using gesture recognizers to dismiss the keyboard because it was the only thing I could think of to dismiss the keyboard when the tableView was not selected (user tapped outside the tableView without selecting a cell). I am working with a search bar so I am not sure how to do that (although I can explore that option). You mentioned "set the requires (to fail) of the other recognizer", how could I go about doing that? – Kevin May 26 '17 at 21:27
  • How about a done button on the keyboard itself? You can require one gesture recognizer to only fire when another one fails. By doing it like this you can prevent your single tap gesture recognizer to not get fired when the long press is fired. It would still not fix your problem that cells are not touchable anymore. For this you'd have to implement the gesture recognizer delegate, get the tough position and manually check if it's inside a tableview cell and then don't let the recognizer capture the touch. probably thers also a way to forward the touch but you'd have to check the documentation. – xxtesaxx May 26 '17 at 21:37
  • Have a look at IQKeyboardManager library. It handles keyboard stuff pretty well and gives you a done button on a keyboard toolbar for free. Also make your keyboard show a done or return button. Thats probably more convenient. Another solution could be to add a UIView on top of your whole tableview when the keyboard shows up and add the gesture recognizer to this view. then once it's tapped and you dismissed the keyboard, remove the view. – xxtesaxx May 26 '17 at 21:39
  • My keyboard has a search button on it already. But I am not sure I understand how that could help. You mentioned that I can prevent single tap gesture to not get fired when long press is fired, but when a user is selecting a table cell with a tap, this wouldn't work would it? You also mentioned to use a UIView on top of a tableView and after adding a gesture recognizer to the view. This is the same issue as a tap in the tableView would not select the cell (as only a long press would). Please let me know if I have interpreted correctly. – Kevin May 26 '17 at 21:55
  • I don't understand why you would want to hide the keyboard in your search controller in the first place but I was just saying that you have a lot of options. Personally I would not use a gesture recognizer on the tableview to dismiss the keyboard. I'd use a keyboard toolbar or the return button of the keyboard (you can make the search button dismiss the keyboard as well) or use didSelectCell to dismiss the keyboard. If you however want to use gesture recognizer on your tableview, it is up to you to process the touch and forward it to the tableview. – xxtesaxx May 26 '17 at 22:08
  • By implementing the UIGestureRecognizerDelegate, you could decide to only capture taps when the keyboard is showing. Then, when you decide not to capture the touch because there is no keyboard, the tableview can receive the touch. For me though that makes no sense because it forces the user to touch twice. Once to dismiss the keyboard and once to tap the cell. – xxtesaxx May 26 '17 at 22:10
  • But as I said, you could also check where the touch happened, get the appropriate cell and forward the touch manually. You might want to read through the UIGestureRecognizer and UIGestureRecognizerDelegate documentation. I know its sometimes hard to grasp but reading it 1-2 times will give you a lot of knowledge and help you understand what is actually happening. :) – xxtesaxx May 26 '17 at 22:11
  • I want to hide the keyboard when the tableViewCell is selected (I already put code in that delegate to dismiss when it is selected), and when the tableView is present but the user taps outside of the tableView to hide the tableView and to dismiss the keyboard (exiting the search). My problem is that I don't want the gestureRecognizer (a tap) to be recognized in the tableView to get rid of the keyboard. I just want the user to be able to select a cell. – Kevin May 26 '17 at 22:14
  • Hmm I think I still not understand you correctly. If you want to capture touches OUTSIDE the table view, why are you adding the gesture recognizer TO the tableview? What do you mean by "when the tableView is present but the user tapps outside the tableview"? isn't the tableview covering the whole screen? – xxtesaxx May 26 '17 at 22:21
  • Ah no, so my storyboard view consists of a bar at the top and the tableView covering maybe a quarter of the view. So when the bar is tapped, the tableView shows up and the user can tap outside of the tableView (some other space) to cancel the search and to hide the tableView. I am adding the gesture recognizer to the view (the whole screen), but I don't want it applied to the tableView. Sorry for the confusion! – Kevin May 26 '17 at 22:23
  • Ah okay. Sounds like the view is covering your tableview and therefore the gesturerecognizer gets the touch. Please try to move the view which covers the screen below your tableview. In the storyboard that means the tableview must be further down in the list and it MUST NOT be a child of the view. a hierarchy could be: level 1->view controller view, level 2->view covering whole screen, also level 2 but in the lust under the view-> the tableview – xxtesaxx May 26 '17 at 22:26
  • Okay, I think we might be on to something. I have edited my question with a picture of what you recommended. Did I do it correctly? Because when I load the VC, it is black. – Kevin May 26 '17 at 22:42
  • Thats not what I meant. I added a screenshot myself. Check it out – xxtesaxx May 26 '17 at 22:53
  • Ah I see, how do I add "View with UIGestureRecognizer" or something similar ? – Kevin May 26 '17 at 22:58
  • I just renamed a plain UIView. Thats not a special view. – xxtesaxx May 26 '17 at 22:59
  • Ok I've added a UIView from the object library and covered the whole VC (I didn't have a view there previously). And after placing the tableView under the view hierarchy, still no luck. – Kevin May 26 '17 at 23:05
  • Hmm maybe you can create a code demo or publish your project somewhere otherwise its hard to tell what could cause side effects – xxtesaxx May 26 '17 at 23:24
  • I think what is happening is that when I reference self.view.addGestureRecognizer(tapGesture), it thinks I am talking about the whole View (the parent), and not the UIView I dragged in (the child). How can I differentiate the two in code? – Kevin May 26 '17 at 23:39
  • 1
    You have to create a @IBOutlet for the view and name it something different than just "view" because each UIViewController already has a property called "view". Then call "myCustomView.addGesture..." – xxtesaxx May 27 '17 at 02:39
  • Glad I was able to help :) – xxtesaxx May 27 '17 at 11:29