问题描述
几年来,我一直在假设如果超级视图及其子视图都具有手势识别器,则子视图将首先接收触摸并取消超视图的手势。直到iOS 7,这个假设从未让我失望,允许我向子视图添加手势,确信superview的手势不会干扰。但是在iOS 7中,超级视图将首先随机接收触摸并取消子视图的手势。这种情况很少发生,这使问题难以发现。
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 cancel out the superview's gesture. Until iOS 7 this assumption never failed me, allowing me to add gestures to subviews confident the superview's gestures wouldn't interfere. But in iOS 7, the superview will randomly receive the touches first and cancel out the subview's gestures. This happens somewhat rarely, which made the problem hard to spot.
我第一次遇到这个问题,因为使用 UITapGestureRecognizer
无法点击的按钮......很少见。通常按钮会工作,直到它们没有。让你有点质疑你的理智。所以我推出了自己的 TapGestureRecognizer
,并发现superview水龙头有时会取消他们的子视图点击。它在任何以前版本的iOS中都没有这样做,但我想知道这种行为是否从未被承诺过。
I first experienced this problem as buttons that couldn't be tapped using UITapGestureRecognizer
... again, very rarely. Usually the buttons would work until they didn't. Made you kind of question your sanity. So I rolled my own TapGestureRecognizer
and discovered that superview taps were canceling their subview's taps on occasion. It's never done this in any previous version of iOS, but I'm wondering if this behavior was simply never promised.
我认为子视图的手势应该是取消它的superview的手势(除非委托另有指定)。这是错误的还是这个错误?
请注意:我不是问如何处理这种情况。我问是否有人知道我的假设是否不正确。我已经重新安排了视图,动态添加/删除手势,并创建了相当复杂的 gestureRecognizer实现:shouldReceiveTouch:
来纠正这种情况。这不好玩,但我可以解决这个问题。
Please Note: I'm not asking how to handle the situation. I'm asking if anyone knows whether my assumption is incorrect. I'm already rearranging views, dynamically adding/removing gestures and creating rather complex implementations of gestureRecognizer:shouldReceiveTouch:
to remedy the situation. It's not fun, but I can work around the problem.
推荐答案
经过大量搜索,我找到了关于Apple消息的讨论与其他用户遇到此问题的电路板:(需要开发人员帐户)。我继续提交了一个错误报告:15331126 (有没有人知道如何链接到错误报告?)。与此同时,我实施了这种解决方法。到目前为止似乎工作正常,但由于这个bug很少见,我可能根本就没有触发它。我将它发布给我的测试版用户,如果我没有得到他们的抱怨(他们一直抱怨),我会认为这可以解决问题。
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;
}
请注意,我的自定义gestureRecognizers现在实现了UIGestureRecognizerDelegate协议(公开地说,原因是你我会在下面看到)。我还在UIGestureRecognizer中添加了几个类别(在上面的代码中使用):
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我不完全确定我需要检查兄弟姐妹,因为我只看到问题出现在superview手势上。但是,我不想抓住这个机会。请注意,我只检查当前视图下方的兄弟姐妹,因为我不想取消当前视图上方的视图手势。
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.
我必须添加实现对于那些将自己设置为自定义识别器代表的类,但它们几乎只是回调给gestureRecognizer:
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 <UIGestureRecognizerDelegate>)gestureRecognizer gestureRecognizer:gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:otherGestureRecognizer];
}
return NO;
}
希望这可以帮助其他人解决问题。
Hope this helps anyone else having the problem.
这篇关于superview的手势是否应取消iOS 7中子视图的手势?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!