UIView, its superview and touchesBegan:

Eduardo Coelho picture Eduardo Coelho · Feb 7, 2011 · Viewed 14.7k times · Source

Suppose I have a UIViewController subclass that takes care of some UIViews. These UIViews are added as subviews of the UIViewController's view property):

UIViewController:

- (void)viewDidLoad {
    UIImageView *smallImageView...
    [self.view addSubview:smallImageView];

    UIButton *button..
    [self.view addSubview:button];

    UIView *bigUIView.. // covers the entire screen (frame = (0.0, 0.0, 1024.0, 768.0))
    [self.view addSubview:bigUIView];
...
}

AFAIK, since the bigUIView is the frontmost view and covers the entire screen, it will receive the touchesBegan:withEvent: and the other views, such as button won't receive any touch event.

In my application bigUIView must be the topmost view because it holds the main user interface objects (CALayers, actually, the main game objects) that, when animated, must be on top of all other secondary UI elements (UIButtons, etc). However, I'd like to be able to still have the UIButtons and other objects in the Responder Chain.

I tried implementing the following in the bigUIView class:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {    
    [self.superview touchesBegan:touches withEvent:event];

    ... hit test the touch for this specific uiview..
}

Notes:

  1. bigUIView's superview refers to the UIViewController's view property, does it propagate the touch event to all of it's subviews?
  2. bigUIView must have userInteractionEnabled = YES because it also handles user input.
  3. I can't bring the button/smallImageView to front because it would appear above the main game objects (sublayers of bigUIView).

Thanks in advance.

Answer

jlehr picture jlehr · Feb 7, 2011

Try overriding pointInside:withEvent: in the bigUIView class to return NO if the point is inside the frame rectangle of one of the other subviews of the background view. Since it's a sibling of these other views, the hit testing mechanism will continue testing the other subviews and find the one corresponding to the point the user touched.

Alos, consider implementing the event phase methods (-touchesBegan:withEvent:, etc.) in your UIViewController subclass rather than in the bigUIView class. iOS inserts view controllers behind their views in the responder chain, so event messages will bubble up to the view controller unless one of the other subviews (for example, a button) intercepts it. The view controller can then send whatever messages you like to any of its views.