UITableView passes touch events to superview when it shouldn't - ios

In the GIKAnimatedCallout sample code, double-tap gestures, two-finger tap gestures, zoom gestures, and pinch gestures are all being passed through from the UITableView to the MKMapView underneath it. I want to stop this from happening. Touch events inside the UITableView should not be passed onto the MKMapView.
I've tried adding a UIGestureRecognizer for taps, and made it an empty method, but these touch events are still sent to the MKMapView as well as the UITableView.
Looking at the UITableView's superview hierarchy through the debugger, I see that the UITableView is a descendant of the MKMapView.
I don't really know how else to approach this problem. Any pointers are appreciated.

if i understand correctly, you want the MKMapView not to react at all if a gesture is made on the UITableView (in the example, the myTableView property of myMKMapView is the UITableView in question). if so, you should implement
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;
in your subclass of MKMapView (make a subclass if you dont have one. i've called the subclass myMKMapView in this example). Start off by making your subclass of MKMapView, myMKMapView, conform to the UIGestureRecognizerDelegate protocol.
in the MKMapView's .h file:
#interface myMKMapView : MKMapView <UIGestureRecognizerDelegate>
After this is done, go into myMKMapView's .m file and implement the following as such:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
UIView *view = [self.view hitTest:[touch locationInView:self.view] withEvent:nil];
if ([view isDescendantOfView:(self.myTableView)]) {
return NO;
}
return YES;
}
This tells myMKMapView that if a gesture is performed on its myTableView property, myMKMapView should ignore it.

Swift 5 version of Pedro Cattori's answer.
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
!(view.hitTest(touch.location(in: view), with: nil)?.isDescendant(of: tableView) == true)
}

Related

iOS how to ignore parent view receive touch event after child view handle it

Please take a look at the picture below:
I have a custom UIControl as RangeSlider which I implemented by follow this tutorial. I place the RangeSlider inside a FilterViewController which can slide in or out.
On class RangeSlider I used 3 methods of UIControl: beginTracking, continueTracking, endTracking to handle touch event when user move the indicator of slider.
On class FilterViewController I used UIPanGestureRecognizer to handle touch event when user slide in or out.
Problem
When I try to move the indicator of slider, the ViewController also move. And the indicator is just move a bit. It seem to be the both of child view and parent view received touch event.
Question
How can I ignore the parent view(ViewController) receive touch event?
You can write this in viewDidLoad().
self.view.isUserInteractionEnabled = false
You should implement method of your PanGestureRecognizer delegate
gestureRecognizerShouldBegin(_:)
edit: please try
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
guard let view = gestureRecognizer.view, view.isKind(of: UIControl.self) else {
return true
}
return false
}
Hope this helps.
This should help within FilterViewController (assuming it is touch delegate)
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if ([touch.view isDescendantOfView:self.tableView]) {
return NO;
}
return YES;
}
Sorry for example in objective-c, you can easily convert it into swift. It means that the table or scrollview you use won't react on touches of its subviews (assuming RangeSlider is descendant subview of table view cell). Let me know if that doesn't help, I forced these issues in past by several different ways!

Adding a UIGestureRecognizer taking priority over all other interactions

When I tap on a UIButton, a UIView MyView appear from the bottom a cover a third of the screen. I would like that when I tap somewhere outside this view, it disappears.
I thought about adding another transparent UIView right under MyView and add a tab gesture on it with the dismiss function but I'm sure there is something cleaner than this.
So I thought about adding the tap gesture MyTapGesture to dismiss MyView on self.view of the UIViewController. The problem is that outside this view, I have other UIControls and gestures that capture also any touch at the same time than MyTapGesture.
How can I make MyTapGesture the priority gesture outside MyView and ignore all other gesture, taps, etc...?
You may have to use the gesture delegate methods to handle two tapGestureRecognizer activate the one you need depending on scenario
#pragma mark - UIGestureRecognizerDelegate methods
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
if ([tapGestureRecognizer1 isEqual:gestureRecognizer]) {
return [tapGestureRecognizer2 isEqual:otherGestureRecognizer];
}
if ([tapGestureRecognizer2 isEqual:gestureRecognizer]) {
return [tapGestureRecognizer1 isEqual:otherGestureRecognizer];
}
return NO;
}

Touch Events on UIView on UITableView

I'm trying to catch the touchesBegan and the touchesMoved events on an UIView.
I have a UITableView; each cell contains a UIView with several controls. One of these controls is a subclass of a UIView with code in the touchesBegan and touchesMoved events.
If this control is not on the tableviewcell, then it works fine. But in this situation, all touches have effect to the tableview, but not to the UIView.
How to ignore the TouchEvents and redirect them to the UIView?
Try setting delaysContentTouches property of the tableview(scrollview) to YES.
Try this one..
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if ([touch.view isDescendantOfView:yourview])
{
return NO;
}
return YES;
}

How to prevent UIView passing touch events to UIView's superview?

I have a UIViewController object (bottomViewController) in the window, and a UIView object (upperView) on the UIViewController.There are some buttons (buttonOne, buttonTwo, buttonThree) on the UIView. The bottomViewController have a UIGestureRecognizer.
Now, I have a touch event on the upperView; the touch point is outside of the buttons. The upperView will pass the event to its superview (bottomViewController).
How can I prevent upperView from passing the event - to which it can't respond - to its superview?
Make use of:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
int the UIGestureRecognizerDelegate
return YES if you should receive touch NO if not, based on what ever logic you want to apply. You have the UITouch and UIGestureRecognizer which both contain lots of useful information.
Remember to set delegate of UIGestureRecognizer to self.
You could assign tags to views and then check for if condition and put up logic into it.

Two UIGestureRecognizers and UIButton

I encountered this problem and was able to resolve it as described.
Gesture recognizer and button actions
But when I added a second UIGestureRecognizer to the same UIView the UIButton selector is not called for the second UIGestureRecognizer, only the first.
So I have a single UIView with two UIGestureRecognizers. There is a UIButton on the UIView.
The UIButton selector always get called correctly after the first UIGestureRecognizer. The first touch on the UIButton for the second UIGestureRecognizer does nothing, but the second touch on the UIButton works as expected.
If I remove the first UIGestureRecognizer from the view then the first UIButton press fires the selector as expected after the second gesture is performed.
Any idea why the first touch on the UIButton doesn't fire the selector but the second does?
try to put his delegate method in your viewController
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
returning YES to this method is guaranteed to allow simultaneous recognition.

Resources