Search code examples
iosuiviewcontrolleruikituiresponderuievent

UIResponder Chain Explanation Needed


I'm having trouble getting my UIButtons, UIScrollViews etc working in this situation:

I have the base UIViewController, which is the root controller of the UIWindow. Above that layer I have some other UIViews added, which I will call the "Middle Layer View". And on the top I have another UIView added for overlay objects.

The Middle Layer View is changed for different views regularly. The UIView it uses is from a UIViewController, made by a NIB file. Here's an example

if ( mode == eModeShowView1 )
    UIViewController* nextController = [[UIViewController alloc] initWithNibName:@"View1"...
else if ( mode == eModeShowView2 )
    UIViewController* nextController = [[UIViewController alloc] initWithNibName:@"View2"...

[UIView insertSubview:nextController.view below:m_overlayView];

Now, when I touch on screen, the first responder is obviously the OverlayView or any UIResponder on the OverlayView that has been touched. The UIEvent of the touch input goes up the view chain but seems to skip the Middle Layer View and the UIResponders on that UIView altogether. It jumps straight to the root UIViewController.

Does anyone know what's going on here?

Could it be solved by somehow creating two UIEvents? One for the Overlay View and one for the Middle Layer View? Is that possible? If so, how?

Any help would be most appreciated. Thanks, Rich


Solution

  • edit1 start:

    you can put a UITapGestureRecognizer to the m_overlayView and initWithTarget:your-middleview action:some-method-in-middleview

    Now, in your middleview you can identify recognizer.state as UIGestureRecognizerStateBegan, Ended etc and do what you want to do.

    edit1 end:

    You can debug it. Just use the logs in touchesbegan in all your controllers. It will be clear by logs the sequence of touch responses.

    Ok.. so this description of method from documentation might answer you. Your m_overlayView and nextController.view are regarding each other as siblings and not superview. So your touch on either of them will not be reported to the other but instead to the base superview which is a common superview to both the siblings.

    Hence you are getting that the middle layer is being bypassed. Actually your middle-layer is a sibling and no more a superview. Hope that at least gives you some way ahead ;)

    insertSubview:belowSubview:
    

    Inserts a view below another view in the view hierarchy.

    (void)insertSubview:(UIView *)view belowSubview:(UIView *)siblingSubview
    

    Parameters:

    view
    

    The view to insert below another view. It’s removed from its superview if it’s not a sibling of siblingSubview.

    siblingSubview:

    The sibling view that will be above the inserted view.

    Discussion:

    This method retains view and sets its next responder to the receiver, which is its new superview.

    Views can have only one superview. If view already has a superview and that view is not the receiver, this method removes the previous superview before making the receiver its new superview.