【问题标题】:Should superview's gesture cancel subview's gesture in iOS 7?在 iOS 7 中,superview 的手势是否应该取消 subview 的手势?
【发布时间】:2013-10-06 08:55:49
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: ios ios7 uigesturerecognizer touch-event


    【解决方案1】:

    经过大量搜索后,我发现在 Apple 的留言板上与其他遇到此问题的用户进行了讨论:Issues with 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;
    }
    

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

    【讨论】:

    • 你有没有从母舰那里得到任何反馈?有一个更清晰的方法/协议来建立排序会更好。 (感谢您的帖子)
    • 不,不是。我提交的雷达最终被删除为“有意行为”。但是,我注意到在更新的 iOS 版本中我没有看到问题弹出,所以我怀疑内部修复了一些问题。
    • 好东西!我现在发现自己给出了一个冗长的序言,说明我所描述的错误是如何被任何理智的人认为是合理的,并试图阐明预期与正确不同的观点。我也有错误按预期返回,后来修复 - 不知道这是怎么发生的。再一次进入突破口! ;-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-08
    • 2020-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-27
    • 2013-10-08
    相关资源
    最近更新 更多