Forwarding UIGesture to views behind Forwarding UIGesture to views behind ios ios

Forwarding UIGesture to views behind


If i undestand your problem correct, you may just add another, clear view with rect, same as you A and B view, and implement all gesture on it: when you do pinch gesture, control subView A, when swipe and tap (single and double) gestures - control subView B. You can do it different ways: via pointers or just sending recived gesture to method in class, wich controls your sub view.

for example:

UISwipeGestureRecognizer *leftSwipe  =  [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(leftSwipe:)];[leftSwipe setDirection:(UISwipeGestureRecognizerDirectionLeft)];leftSwipe.delegate  =   subViewAcontroller;[clearView addGestureRecognizer:leftSwipe];[leftSwipe release];UISwipeGestureRecognizer *rightSwipe  =  [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(rightSwipe:)];[rightSwipe setDirection:(UISwipeGestureRecognizerDirectionRight)];rightSwipe.delegate   =   subViewAcontroller;[clearView addGestureRecognizer:rightSwipe];[rightSwipe release];UIPinchGestureRecognizer *pinch   =  [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(handlePinch:)];pinch.delegate    =   subViewBcontroller;[clearView addGestureRecognizer:pinch];[pinch release];

or:

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{    if ([gestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]]) {        NSLog(@"pinchGesture");        [subViewBcontroller solvePinchGesture: gestureRecognizer];    }//etc    return YES;}


The pinch gesture will Never received by the aView, because you view hierarchy is incorrect.

---> A superView  | ---> SubView - A  | ---> SubView - B (exactly on top of A, completely blocking A).

bView will captures all multi-touches including the pinch gesture, but bView will not handle the pinch gesture, so it will pass it to Next responder in the Responder chain, i.e. the superView of bView or the viewController of bView. The pinch event will never passed to its sibling views, because they are in parallel (no parent-child or view-viewController relationship).

You can change your view hierarchy as below:

---> A superView  | ---> SubView - A        |       ---> SubView - B (child view of b, exactly on top of A, completely blocking A)- (void)viewDidLoad {    [super viewDidLoad];    aView = [[UIView alloc] initWithFrame:self.view.bounds];    aView.backgroundColor = [UIColor blueColor];    bView = [[UIView alloc] initWithFrame:self.view.bounds];    bView.backgroundColor = [UIColor redColor];    [self.view addSubview:aView];    [aView addSubview:bView];    UISwipeGestureRecognizer *leftSwipe  =  [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(leftSwipe:)];    [leftSwipe setDirection:(UISwipeGestureRecognizerDirectionLeft)];    leftSwipe.delegate  =   self;    [bView addGestureRecognizer:leftSwipe];    UISwipeGestureRecognizer *rightSwipe  =  [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(rightSwipe:)];    [rightSwipe setDirection:(UISwipeGestureRecognizerDirectionRight)];    rightSwipe.delegate   =   self;    [bView addGestureRecognizer:rightSwipe];    UIPinchGestureRecognizer *pinch   =  [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(handlePinch:)];    pinch.delegate    =   self;    [aView addGestureRecognizer:pinch];}

Please get more information from below link:https://developer.apple.com/library/ios/#documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/EventsiPhoneOS/EventsiPhoneOS.html#//apple_ref/doc/uid/TP40009541-CH2-SW1

--> Important note of the event passing in the responder chain "When the system delivers a touch event, it first sends it to a specific view. For touch events, that view is the one returned by hitTest:withEvent:; for “shaking”-motion events, remote-control events, action messages, and editing-menu messages, that view is the first responder. If the initial view doesn’t handle the event, it travels up the responder chain along a particular path:

  1. The hit-test view or first responder passes the event or message to its view controller if it has one; if the view doesn’t have a view controller, it passes the event or message to its superview.
  2. If a view or its view controller cannot handle the event or message, it passes it to the superview of the view.
  3. Each subsequent superview in the hierarchy follows the pattern described in the first two steps if it cannot handle the event or message.
  4. The topmost view in the view hierarchy, if it doesn’t handle the event or message, passes it to the window object for handling.
  5. The UIWindow object, if it doesn’t handle the event or message, passes it to the singleton application object."

my answer above is not the only solution, what you need to do is make swipe and pinch gesture handling logics in the same responder chain, so the un-handle pinch gesture event will passed to the correct responder. For example, you can omit subview b, and add the swipe left/right gestures to superView of aView.


I did something similar some time ago. I wanted to do two different things with one finger and two or more fingers. My solution might need some tweak for you and i can't ensure everything will work exactly the same in your code-environment. I did not find proper documentation of hitTest and why it is called multiple times in a row. So i did some testing and came to a solution, how to separate one and multi-finger gestures, which worked very well for my needs.

I had this view hierarchy:

---> A superView  | ---> ScrollView - A - all touches | ---> ScrollView - B - only two+ finger scroll (exactly on top of A, completely blocking A).

I implemented the switch in hitTest of the superView:

BOOL endDrag; // indicates scrollviewB did finishBOOL shouldClearHitTest; // bool to help calling the method clearHitTest only once.BOOL multiTouch; // needed for the method clearHitTest to know if a multi-touch is detected or notNSMutableArray *events; // store all events within one eventloop/touch;- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {    if (!endDrag) {        if (!shouldClearHitTest) { // as hitTest will be called multible times in one event-loop and i need all events, i will clean the temporaries when everything is done            shouldClearHitTest = YES;            [[NSRunLoop mainRunLoop] performSelector:@selector(clearHitTest) target:self argument:nil order:1 modes:[NSArray arrayWithObject:NSRunLoopCommonModes]];        }        [events addObject:event]; // store the events so i can access them after all hittests for one touch are evaluated        if (event.type == UIEventTypeTouches && ([_events count] > 3 || [[event allTouches] count] > 0 || _currentEvent)) { // two or more fingers detected. at least for my view hierarchy            multiTouch = YES;            return scrollViewB;        }    }else {        endDrag = NO;    }    return scrollViewA;}- (void)clearHitTest {    if (shouldClearHitTest) {        shouldClearHitTest = NO;        [events removeAllObjects];        if (multiTouch) {           // Do some special stuff for multiTouch        }        multiTouch = NO;    }}