9

几年来,我一直在假设如果父视图及其子视图都具有手势识别器,则子视图将首先接收触摸并取消父视图的手势。在 iOS 7 之前,这个假设从未让我失望,允许我向子视图添加手势,确信超级视图的手势不会干扰。但在 iOS 7 中,superview 会先随机接收到触摸并取消 subview 的手势。这种情况很少发生,这使得问题很难被发现。

我第一次遇到这个问题是因为按钮无法再次使用UITapGestureRecognizer......再次点击,非常罕见。通常这些按钮会起作用,直到它们不起作用。让你有点怀疑自己的理智。所以我滚动了自己的TapGestureRecognizer,发现超级视图点击有时会取消他们子视图的点击。在任何以前的 iOS 版本中从未这样做过,但我想知道这种行为是否从未被承诺过。

我认为子视图的手势应该取消它的超级视图的手势(除非代表另有说明)。这是错误的还是错误的?

请注意:我不是在问如何处理这种情况。我在问是否有人知道我的假设是否不正确。我已经在重新排列视图,动态添加/删除手势并创建相当复杂的实现gestureRecognizer:shouldReceiveTouch:来纠正这种情况。这不好玩,但我可以解决这个问题。

4

1 回答 1

8

经过大量搜索后,我发现与其他遇到此问题的用户在 Apple 的留言板上进行了讨论:UITapGestureRecognizer 问题(需要开发人员帐户)。我继续提交了一个错误报告:15331126 (有人知道如何链接到错误报告吗?)。与此同时,我实施了这个解决方法。到目前为止,它似乎正在工作,但由于这个错误非常罕见,我可能根本还没有触发它。我将它发布给我的测试版用户,如果我没有收到他们的投诉(他们一直在抱怨),我会认为这可以解决问题。

更新: 这个解决方案已经解决了这个问题。经过数十名用户的几周使用,我没有遇到过手势问题。

我的大部分手势都是习惯的。我将它们更改为自己的代表并实施:

- (BOOL) gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
    if (gestureRecognizer == self){
        if ([otherGestureRecognizer isMemberOfClass:self.class]){
            if ([self isGestureRecognizerInSuperviewHierarchy:otherGestureRecognizer]){
                return YES;
            } else if ([self isGestureRecognizerInSiblings:otherGestureRecognizer]){
                return YES;
            }
        }
    }
    return NO;
}

请注意,我的自定义手势识别器现在实现了 UIGestureRecognizerDelegate 协议(公开的,原因您将在下面看到)。我还在 UIGestureRecognizer 中添加了几个类别(在上面的代码中使用):

- (BOOL) isGestureRecognizerInSiblings:(UIGestureRecognizer *)recognizer{
    UIView *superview = self.view.superview;
    NSUInteger index = [superview.subviews indexOfObject:self.view];
    if (index != NSNotFound){
    for (int i = 0; i < index; i++){
            UIView *sibling = superview.subviews[i];
            for (UIGestureRecognizer *viewRecognizer in sibling.gestureRecognizers){
                if (recognizer == viewRecognizer){
                    return YES;
                }
            }
        }
    }
    return NO;
}
- (BOOL) isGestureRecognizerInSuperviewHierarchy:(UIGestureRecognizer *)recognizer{
    if (!recognizer) return NO;
    if (!self.view) return NO;
    //Check siblings
    UIView *superview = self.view;
    while (YES) {
        superview = superview.superview;
        if (!superview) return NO;
        for (UIGestureRecognizer *viewRecognizer in superview.gestureRecognizers){
            if (recognizer == viewRecognizer){
                return YES;
            }
        }
    }
}

我不完全确定我需要检查兄弟姐妹,因为我只看到超级视图手势出现问题。然而,我不想抓住这个机会。请注意,我只检查当前视图“下方”的兄弟姐妹,因为我不想取消当前视图“上方”的视图手势。

我必须为那些将自己设置为自定义识别器代表的类添加实现,但它们几乎只是回调手势识别器:

- (BOOL) gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
    if ([gestureRecognizer respondsToSelector:@selector(gestureRecognizer:shouldBeRequiredToFailByGestureRecognizer:)]){
        return [(id <UIGestureRecognizerDelegate>)gestureRecognizer gestureRecognizer:gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:otherGestureRecognizer];
    }
    return NO;
}

希望这可以帮助其他遇到问题的人。

于 2013-10-29T13:40:19.143 回答