1

guys, I'm totally new to Objective C and XCode, so don't be too harsh on me for such a question. In fact, this is my first question on StackOverflow ever. The problem is the following:

I need functionality for closing the keyboard when tapping or scrolling anywhere outside the textField that is currently first responder.

I managed to implement it for tap and horizontal swipes with the following code (right swipe example):

UISwipeGestureRecognizer *swipeGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(closeKeyboard:)];
swipeGestureRecognizer.direction = UISwipeGestureRecognizerDirectionRight;
[self.tableView addGestureRecognizer:swipeGestureRecognizer];
swipeGestureRecognizer.cancelsTouchesInView = NO;        

And in fact, later I figured out how to do it using solely interface builder. But vertical swipes just would not work, neither when I do them programmatically, nor through the IB. I suspect that the problem is that my tableView scrolls vertically on the screen, thereby preventing the call of the swipe, but I still have no idea on how to overcome this issue.

I would greatly appreciate your help! Thanks.

2 Answers2

0

I saw, that you are trying to add this vertical gesture to a tableView. So you don't need to add a vertical swipe gesture . You have to implement UIScrollViewDelegate protocol, and implement the -scrollViewDidScroll: or -scrollViewWillBeginDragging: methods. In these methods you can catch if your tableview scrolling, and if your tableView is scrolling, call your closeKeyboard method

Magyar Miklós
  • 4,182
  • 2
  • 24
  • 42
  • Thanks for the reply, it does work in most cases, but in the case where I am about to enter the textField and it needs to scroll up automatically (like when the textField is in the bottom of the tableView), it triggers the scrollViewDidScroll method, and the keyboard hides immediately, which is no good. Thus, I need a way to distinguish when the scroll is triggered by the user vs. automatically. – Alexey Panyushkin Oct 17 '13 at 07:29
0

the UITableView basically uses UIScrollView & when you implement the UITableView delegate, you also implement the UIScrollView delegate (because behind the scenes, the UITableViewDelegate has implemented the UIScrollViewDelegate)
You do not have to manually implement the UIScrollViewDelegate & you can simply start using any UIScrollView delegates you want such as the -(void)scrollViewDidScroll:

But if you want vertical swipes to work on the tableview then it can be done in the following dirty & totally buggy technique. (Basically this is how NOT to do it)

  1. MAIN property is setDelaysContentTouches on your tableView object to NO.
  2. setDirection on your UISwipeGestureRecognizer object to detect vertical up & vertical down swipes.
  3. Set the swipe gesture onto the tableView object.

example:

[self.tableView setDelaysContentTouches:NO];

UISwipeGestureRecognizer *mySwipe = [[UISwipeGestureRecognizer alloc]
                                                    initWithTarget:self
                                                    action:@selector(closeKeyboard:)];
[mySwipe setDirection: UISwipeGestureRecognizerDirectionUp | UISwipeGestureRecognizerDirectionDown];
[self.tableView addGestureRecognizer:mySwipe];

Finally, you'll get it to work but it works real bad.

  • Most of the times, the swipe is ignored since you need to swipe really really fast and cover a decent distance within the swipe action.
  • When the swipe works, the table does not scroll.

So, as you see, it's really sad and dirty thing to do.

The reason is that the scrollView handles the content touches in a very specific way.

To decide if the touch is to be handled or to be forwarded, the UIScrollView starts a timer when you first touch it:

  • If you haven't moved your finger significantly within 150ms, it passes the event on to the inner view.

  • If you have moved your finger significantly within 150ms, it starts scrolling (and never passes the event to the inner view). Note: how when you touch a table (which is a subclass of scroll view) and start scrolling immediately, the row that you touched is never highlighted.

  • If you have not moved your finger significantly within 150ms and UIScrollView started passing the events to the inner view, but then you have moved the finger far enough for the scrolling to begin, UIScrollView calls touchesCancelled on the inner view and starts scrolling. Note: how when you touch a table, hold your finger a bit and then start scrolling, the row that you touched is highlighted first, but de-highlighted afterwards.

These sequence of events can be altered by configuration of UIScrollView:

  • If delaysContentTouches is NO, then no timer is used — the events immediately go to the inner control (but then are canceled if you move your finger far enough)

  • If cancelsTouches is NO, then once the events are sent to a control, scrolling will never happen.

Note that it is UIScrollView that receives all touchesBegin, touchesMoved, touchesEnded and touchesCanceled events from CocoaTouch (because its hitTest tells it to do so). It then forwards them to the inner view if it wants to, as long as it wants to.

source: https://stackoverflow.com/a/844627/2857130

Community
  • 1
  • 1
staticVoidMan
  • 19,275
  • 6
  • 69
  • 98