Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iphone/ipad - parent UIView is blocking touches from getting to subviews - why?

I have a UIView which has a bunch of subviews. The subviews should be able to receive touch events, but for some reason the parent UIView takes the touch and does not pass it on. I have created it in a very standard way like I always create views:

UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0,0,1024,768)];
    self.mainView = myView;
    [myView release];

    [self.view addSubview:self.mainView];

Then I create subviews and add them as normal:

[self.mainView addSubview:someOtherView];

I know self.mainView is getting the touch events when I listen in the main UIWindow:

VIEW: <UIView: 0x8d34aa0; frame = (0 0; 1024 768);

But why in the world can I not get the subviews to receive touches? I don't understand why this happens sometimes. I am not changing any default properties of mainView.

like image 349
sol Avatar asked Sep 06 '10 20:09

sol


2 Answers

Had to do with the frame of the parent view. If the frame doesn't enclose the subviews they won't receive touches.

like image 186
sol Avatar answered Nov 12 '22 11:11

sol


UIView touches do not get passed to subviews if they lie outside of the superview's bounds as mentioned by the solution.

However if you want these subviews to respond to touch, override hitTest:withEvent: of the superview.

Documentation on Event Delivery

Touch events. The window object uses hit-testing and the responder chain to find the view to receive the touch event. In hit-testing, a window calls hitTest:withEvent: on the top-most view of the view hierarchy; this method proceeds by recursively calling pointInside:withEvent: on each view in the view hierarchy that returns YES, proceeding down the hierarchy until it finds the subview within whose bounds the touch took place. That view becomes the hit-test view.

  1. Create a subclass of UIView (or other UIView subclass).
  2. Override hitTest:withEvent.
  3. Use this UIView subclass as the superview, so subview can respond to touches.

Add method below in subclass:

(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    NSEnumerator *reverseE = [self.subviews reverseObjectEnumerator];
    UIView *iSubView;

    while ((iSubView = [reverseE nextObject])) {

        UIView *viewWasHit = [iSubView hitTest:[self convertPoint:point toView:iSubView] withEvent:event];
        if(viewWasHit) {
            return viewWasHit;
        }

    }
    return [super hitTest:point withEvent:event];
}

Note: Reverse enumerator used since subviews are ordered from back to front and we want to test the front most view first.

like image 12
Min Tsai Avatar answered Nov 12 '22 12:11

Min Tsai