memical memical - 1 month ago 17
iOS Question

How to send the touch events of UIScrollView to the view behind it?

i have a transparent UIScrollView on top of another view.

the scroll view has content - text and images, used to display info.

the view behind it has some images that the user should be able to tap on.
and the content over them is scrollable using the mentioned scrollview.

i want to be able to normally use the scroll view (no zoom though), but when that scroll view is not actually scrolling to let the tap events through to the view behind it.

using a combination of the touch and scroll events i can determine when to let the taps through.
but the view behind it still it does not receive them.

i have tried using something like this for all touch events:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(@"touchesBegan %@", (_isScrolling ? @"YES" : @"NO"));

if(!_isScrolling)
{
NSLog(@"sending");
[self.viewBehind touchesBegan:touches withEvent:event];
}
}


but it does not work.

also in my case i cannot really apply the hitTest and pointInside solutions, given the use case that i have.

Answer

First off UIScrollViews only inherently recognize UIPanGestureRecognizers and UIPinchGestureRecognizers so you need to add a UITapGestureRecognizer to the UIScrollView so it can recognize any tapping gestures as well:

UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];

// To prevent the pan gesture of the UIScrollView from swallowing up the
// touch event
tap.cancelsTouchesInView = NO;

[scrollView addGestureRecognizer:tap];

Then once you receive that tap gesture and the handleTap: action is triggered, you can use locationInView: to detect whether the tap gesture's position is in fact within the frame of one of the images below your scroll view, for example:

- (void)handleTap:(UITapGestureRecognizer *)recognizer {

    // First get the tap gesture recognizers's location in the entire 
    // view's window
    CGPoint tapPoint = [recognizer locationInView:self.view];

    // Then see if it falls within one of your below images' frames
    for (UIImageView* image in relevantImages) {

        // If the image's coordinate system isn't already equivalent to
        // self.view, convert it so it has the same coordinate system
        // as the tap.
        CGRect imageFrameInSuperview = [image.superview convertRect:image toView:self.view]

        // If the tap in fact lies inside the image bounds, 
        // perform the appropriate action.
        if (CGRectContainsPoint(imageFrameInSuperview, tapPoint)) {
            // Perhaps call a method here to react to the image tap
            [self reactToImageTap:image];
            break;
        }
    }
}

This way, the above code is only performed if a tap gesture is recognized, your program only reacts to a tap on the scroll view if the tap location falls within an image; otherwise, you can just scroll your UIScrollView as usual.

Comments