将UIGesture转发给背后的观点

时间:2012-02-09 11:24:32

标签: iphone ios ipad touch uigesturerecognizer

我正在使用iphone(iOS 4.0或更高版本)应用,并且在多个视图之间遇到触摸处理问题。我有这样的视图结构

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

enter image description here

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

现在我的要求就是这个。

  1. SubView B应该接收所有滑动和点按(单和双) 手势。
  2. SubView A应接收所有捏合手势。
  3. 这是我为视图添加手势识别器的方式

    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的用户交互,当识别到捏合手势时,希望剩余部分的手势将被SubView A接收。也没有这样的运气..

    这就是我现在的立场。我看到了this个问题,其中接受的答案涉及财产cancelsTouchesInView。但我相信cancelsTouchesInView只取消特定的触摸事件,不要转发它。

    任何其他方式来达到我的要求?我准备好处理你提供的任何暗示。

    编辑:BOUNTY TIME

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

5 个答案:

答案 0 :(得分:18)

如果我没有正确解决您的问题,您可以添加另一个带有rect的清晰视图,与A和B视图相同,并在其上实现所有手势:当您执行捏合手势时,控制子视图A,当滑动并点按(单和双)手势 - 控制子视图B.你可以采用不同的方式:通过指针或只是将复活的手势发送到课堂上的方法,它控制你的子视图。

例如:

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

答案 1 :(得分:15)

aView从未收到过捏合手势,因为您查看的层次结构不正确。

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

bView将捕获所有多点触摸,包括捏合手势,但bView将不会处理捏合手势,因此它会将其传递给Responder链中的Next响应者,即bView的superView或bView的viewController。 pinch事件永远不会传递给它的兄弟视图,因为它们是并行的(没有parent-child或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:;用于”摇动“ - 运动事件,远程控制事件,动作消息,和编辑菜单消息,该视图是第一个响应者。如果初始视图不处理该事件,它沿着特定路径沿着响应者链向上移动:

  1. 命中测试视图或第一响应者将事件或消息传递给其视图控制器(如果有);如果视图没有视图控制器,它会将事件或消息传递给其超级视图。
  2. 如果视图或其视图控制器无法处理事件或消息,则会将其传递给视图的超级视图。
  3. 层次结构中的每个后续超级视图都遵循前两个步骤中描述的模式,如果它无法处理事件或消息。
  4. 视图层次结构中最顶层的视图,如果它不处理事件或消息,则将其传递给窗口对象进行处理。
  5. UIWindow对象,如果它不处理事件或消息,则将其传递给单例应用程序对象。“
  6. 我上面的回答并不是唯一的解决方案,您需要做的是在同一个响应程序链中进行滑动和捏合手势处理逻辑,因此未处理的捏合手势事件将传递给正确的响应者。例如,您可以省略子视图b,并将滑动左/右手势添加到aView的superView。

答案 2 :(得分:1)

我前段时间做过类似的事情。我想用一根手指和两根或多根手指做两件不同的事情。我的解决方案可能需要一些调整,我不能确保在代码环境中一切都会完全相同。我没有找到适当的hitTest文档以及连续多次调用它的原因。所以我做了一些测试并找到了解决方案,如何分离一个和多个手指的手势,这非常适合我的需求。

我有这个视图层次结构:

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

答案 3 :(得分:0)

我建议您在需要的地方使用以下代码可以帮助您。

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

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

答案 4 :(得分:0)

如果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=....