Question

I want to display a map view as a permanent background while other views are displayed on top of it (I'm going to set the alpha of the top view to something like 0.9 so the map is just faintly visible underneath) and at some points the map get revealed.

I have a container view which is layered on top of the map view and I would like to know if touch events that occur within the bounds of the container view can be passed to the map view so that it can be scrolled etc. Here's a sketch project showing an example of the architecture.enter image description here

enter image description here

(The Container view is on top of the bottom half of the map view, the container view and contained View Controller's view's alphas are both 0, so to the user the map is visible on the entire screen).

Its easy to forward the touch events occurring within the Contained View Controller's views or child view controllers to the Map Background View Controller.

If I do something like pass the touch event to the map view like this

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    MapBackgroundViewController *parent = (MapBackgroundViewController *) self.parentViewController;
    [parent.mapView touchesBegan:touches withEvent:event];
}

then nothing happens.

Is there a way of passing the touch events to the map view such that it will scroll etc.?

Was it helpful?

Solution

Yes, you can do this.

What I do is subclass UIView and override hitTest:withEvent: such that touches are passed through unless a subview is touched. Something like this:

@implementation PassthroughView

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    UIView *view = [super hitTest:point withEvent:event];
    return view == self ? nil : view;
}

@end

Then I assign this class to my container view and the contained view controller's main view in IB. So you can still interact with the content of the contained view controller, but touches on the container itself get passed through to the map.

OTHER TIPS

You can pack your overlay views all into one container view, in which you then override -pointInside:withEvent: to return NO:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    return NO;
}

This will make the view effectively "untappable".

Alternatively you can also override -hitTest:withEvent: to return nil.

Simply setting userInteractionEnabled to NO won't work unfortunately, since the taps will still arrive in the view and be swallowed.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top