如何排查触发UIGestureRecognizerStateCancelled的原因?
排查UIGestureRecognizer被意外Cancelled的实用思路
这种情况确实挺闹心的——明明没手动加其他手势或滚动视图,自己的手势刚触发began就被砍到cancelled了。结合你提到的调用栈信息,我给你几个针对性的排查方向:
深挖调用栈的细节
仔细盯着调用栈里- [UIGestureRecognizer setState:]之前的每一行调用:- 如果是系统手势拦截,大概率会出现
UIScrollView、_UISystemGestureGateGestureRecognizer这类系统相关类的调用; - 如果是自定义代码拦截,可能会看到你项目里的视图控制器/视图的触摸处理方法(比如
touchesBegan:withEvent:),要是这些方法里没正确调用super或者做了额外的触摸拦截逻辑,也会干扰手势状态。
- 如果是系统手势拦截,大概率会出现
用手势代理抓出拦截者
给你的手势设置delegate,实现这两个代理方法,直接打印所有和当前手势交互的其他手势:- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { NSLog(@"当前手势被要求让位于:%@", otherGestureRecognizer); return NO; } - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { NSLog(@"当前手势要求:%@ 先失败", otherGestureRecognizer); return NO; }另外还可以在
gestureRecognizerShouldBegin:里遍历整个视图层级的手势,看看有没有隐藏的“黑手”:- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { // 打印当前视图的所有手势 for (UIGestureRecognizer *gr in self.view.gestureRecognizers) { NSLog(@"当前视图手势:%@", gr); } // 逐层向上打印父视图的手势,直到window UIView *superView = self.view.superview; while (superView) { for (UIGestureRecognizer *gr in superView.gestureRecognizers) { NSLog(@"父视图[%@]的手势:%@", superView, gr); } superView = superView.superview; } return YES; }排查系统级手势冲突
要是你的页面在导航控制器里,iOS自带的侧滑返回手势(UIScreenEdgePanGestureRecognizer)很可能和你的手势冲突。可以临时禁用侧滑返回测试:self.navigationController.interactivePopGestureRecognizer.enabled = NO;另外也可以在开发者选项里临时关闭控制中心、通知中心的访问权限,排除系统全局手势的干扰。
检查视图交互状态与层级
- 确认你的手势所在视图及其所有父视图的
userInteractionEnabled都是YES,万一某个父视图被意外设为NO,触摸事件会直接“跑偏”; - 用Xcode的
Debug View Hierarchy工具查看视图层级,看看有没有透明视图覆盖在你的手势视图上面——这类视图可能悄悄拦截了触摸事件。
- 确认你的手势所在视图及其所有父视图的
内容的提问来源于stack exchange,提问作者Chris Jones
相关产品推荐
相关产品推荐

