将UIGesture转发到后面的视图

我正在iphone(iOS 4.0或更高版本)的应用程序,并在多个视图之间的触摸处理有一些麻烦。 我有这样的视图结构

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

在这里输入图像说明

基本上我有一个superView,并且兄弟姐妹子视图A和B.B具有与A相同的框架,因此完全隐藏A.

现在我的要求是这样的。

  1. 子视图B应该接收所有轻扫和轻击(单和双)手势。
  2. 子视图A应该收到所有捏手势。

这是我如何添加手势识别器的意见

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

我做了一些研究,对我来说UIGestureRecognizerDelegate看起来很有希望,我实现了委托方法

 - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer 

我为SubView B返回NO,希望底层视图将得到这些事件。 没有这样的运气,但

 - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{ if ([gestureRecognizer isKindOfClass:[UIPinchGestureRecognizer class]] && [gestureRecognizer view] == bView) { NSLog(@"pinchGesture"); //bView.userInteractionEnabled = NO; return NO; } return YES; } 

然后,我禁用了SubView B在代表callback中的用户交互(在上面的代码块中的注释代码),当捏手势被识别时,希望剩下的部分手势将被SubView A接收。

所以这就是我现在的立场。 我已经看到了这个问题,接受的答案涉及属性cancelsTouchesInView 。 但我相信取消触摸cancelsTouchesInView只取消一个特定的触摸事件,不转发。

任何其他方式来实现我的要求? 我准备根据你提供的任何提示工作。

编辑:美好的时光

我所谓的subView A实际上是第三方库的View类的一个实例,它需要所有的触摸,我没有任何手势的控制。 我想要左右滑动的不同实现,我想捏,轻拍等工作,就像它正在与这个第三方视图工作。 所以我在A(SubView B)的顶部放置一个视图来左右滑动。 但是现在我想将其他手势事件转发到底层库。

如果我解决你的问题是正确的,你可以添加另一个清晰的视图与矩形,与你A和B视图一样,并实现所有的手势:当你捏手势,控制子视图A时,轻扫和单击双)手势 – 控制子视图B.你可以做不同的方式:通过指针或只是发送recived手势类中的方法,这将控制你的子视图。

例如:

 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]; 

要么:

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

夹点手势将永远不会被aView接收,因为您的视图层次结构不正确。

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

bView将捕获包括捏手势的所有多触摸,但是bView不会处理捏手势,所以它将它传递给响应者链中的下一响应者,即bView的超视图或bView的视图控制器。 捏事件将永远不会传递给它的同级视图,因为它们并行(没有父子关系或view-viewController关系)。

你可以改变你的视图层次如下:

 ---> 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]; } 

请从下面的链接获取更多信息: https : //developer.apple.com/library/ios/#documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/EventsiPhoneOS/EventsiPhoneOS.html#//apple_ref/doc/uid/TP40009541-CH2-SW1

– >传递给响应者链的事件的重要注意事项“当系统传递一个触摸事件时,它首先将其发送到一个特定的视图,对于触摸事件,该视图是由hitTest:withEvent返回的视图: “动作事件,远程控制事件,动作消息和编辑菜单消息,视图是第一响应者,如果初始视图不处理事件,则沿着特定的path向上传递响应者链:

  1. 命中testing视图或第一响应者将事件或消息传递给它的视图控制器(如果有); 如果视图没有视图控制器,它将事件或消息传递给它的超级视图。
  2. 如果视图或其视图控制器无法处理该事件或消息,则将其传递给视图的超级视图。
  3. 如果不能处理事件或消息,则层次结构中的每个后续超级视图都遵循前两个步骤中描述的模式。
  4. 如果视图层次结构中最顶层的视图不处理事件或消息,则将其传递给窗口对象进行处理。
  5. 如果UIWindow对象不处理事件或消息,则将其传递给单例应用程序对象。

我上面的答案不是唯一的解决scheme,你需要做的是在相同的响应者链中进行滑动和捏手势处理逻辑,所以不处理捏手势事件将传递给正确的响应者。 例如,您可以省略子视图b,并将左右滑动手势添加到aView的超级视图。

我前段时间做了类似的事情。 我想用一个手指和两个或更多的手指做两件不同的事情。 我的解决scheme可能需要一些调整,我不能确保你的代码环境中的一切都会完全相同。 我没有find适当的hitTest文档,为什么它连续多次被调用。 所以我做了一些testing,得出了一个解决scheme,如何分离一个和多个手指的手势,这对我的需求非常好。

我有这个视图层次结构:

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

我在superView的hitTest中实现了这个开关:

 BOOL endDrag; // indicates scrollviewB did finish BOOL 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 not NSMutableArray *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; } } 

我build议你在需要的地方使用下面的代码行可以帮助你。

 //--->for bview gesture to detect swipe [pinch requireGestureRecognizerToFail:leftSwipe]; && [pinch requireGestureRecognizerToFail:rightSwipe]; //--->for aview gesture to detect pinch [rightSwipe requireGestureRecognizerToFail:rightSwipe]; || [leftSwipe requireGestureRecognizerToFail:pinch]; 

如果bView有捏手势。 从bView的捏手势动作,如果称为aView的捏手势动作,然后…

 UIPinchGestureRecognizer *pinchA = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(handlePinchA:)]; [aView addGestureRecognizer:pinchA]; [pinchA release]; UIPinchGestureRecognizer *pinchB = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(handlePinchB:)]; [bView addGestureRecognizer:pinchB]; [pinchB release]; -(void)handlePinchA:(UIGestureRecognizer*)gestureRecognizer { NSLog(@"handlePinch on A"); } -(void)handlePinchB:(UIGestureRecognizer*)gestureRecognizer { NSLog(@"handlePinch on B"); [self handlePinchA:gestureRecognizer]; } 

aView是第三方库。 你可以从外面调用handlePinchA方法吗? NSLog的gestureRecognizers打印我action = handlePinchA

 NSLog(@"gestureRecognizers %@", [aView gestureRecognizers]); 

打印我:

 gestureRecognizers ( "<UIPinchGestureRecognizer: 0x8b3e500; state = Possible; view = <UIView 0x8b2f470>; target= <(action=handlePinchA:, target=....