Should superview's gesture cancel subview's gesture in iOS 7?

后端 未结 1 1756
轻奢々
轻奢々 2021-01-02 09:41

For several years now I\'ve operated under the assumption that if a superview and its subview both have gesture recognizers, the subview would receive the touches first and

1条回答
  •  傲寒
    傲寒 (楼主)
    2021-01-02 10:27

    After a lot of searching around I found a discussion on Apple's message boards with other users that are having this problem: Issues with UITapGestureRecognizer (developer account required). I went ahead and submitted a bug report: 15331126 (does anyone know how to link to bug reports anymore?). In the meantime, I implemented this workaround. So far it seems to be working, but since the bug is so rare I may simply not have triggered it yet. I'm releasing it to my beta users and if I get no complaints from them (who have been complaining) I'll assume this fixes the issue.

    UPDATE: This solution has fixed the problem. After weeks of use by dozens of users I haven't had a single issue with gestures.

    Most of my gestures are custom. I altered them to be delegates of themselves and implemented:

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

    Note that my custom gestureRecognizers implement the UIGestureRecognizerDelegate protocol now (publically, for reasons you'll see below). I also added a couple of categories to UIGestureRecognizer (used in the above code):

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

    I'm not entirely sure that I need to check for siblings as I've only seen the issue occur with superview gestures. However, I didn't want to take that chance. Note that I only check for siblings "below" the current one as I don't want to cancel view gestures "above" the current view.

    I had to add implementations for for those classes that set themselves as delegates of the custom recognizers, but they pretty much just call back to the gestureRecognizer:

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

    Hope this helps anyone else having the problem.

    0 讨论(0)
提交回复
热议问题