Search code examples
iosobjective-cparent-childuitouchuiresponder

Prevent parent view controller from receiving UITouch in child controller


So, in my app, then a map annotation is pressed, It reveals a modal view controller. Then when an element that modal controller is pressed, I open another, smaller controller. In both controllers, I have implemented the method

- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];

    CGPoint touchPoint = [touch locationInView:self.view];

    if (!CGRectContainsPoint([self.view viewWithTag:21].frame, touchPoint)) {
        [self dismissViewControllerAnimated:YES completion:nil];
    }
}

Here is an image that shows my layout: Layout Image

My problem is that when I touch in yellow circle one, the second modal dismisses, and after that, the first modal dismisses. SO, how can I prevent the first modal from receiving the touch.

PS: both modals are transparent UIViews, with smaller views inside them to display the content.


Solution

  • Obviously the event is passed through the view controller to the next responder.

    In the class reference of UIResponder.

    The default implementation of this method does nothing. However immediate UIKit subclasses of UIResponder, particularly UIView, forward the message up the responder chain. To forward the message to the next responder, send the message to super (the superclass implementation); do not send the message directly to the next responder. For example,

    [super touchesMoved:touches withEvent:event];

    If you override this method without calling super (a common use pattern), you must also override the other methods for handling touch events, if only as stub (empty) implementations.

    So if you don't want the event to forward to the next responder, you should override the other methods.

    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    }
    
    - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    }
    
    - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
        UITouch *touch = [touches anyObject];
        CGPoint touchPoint = [touch locationInView:self.view];
    
        if (!CGRectContainsPoint([self.view viewWithTag:21].frame, touchPoint)) {
            [self dismissViewControllerAnimated:YES completion:nil];
        }
    }
    
    - (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    }