VC 包含中的 UINavigationController 点击区域问题

Tap region issues with UINavigationController in VC containment

我有一个 iOS 应用程序,我在其中将 UINavigationController 作为 child 视图控制器添加到主屏幕。它是垂直排列的,因此导航控制器占据了主视图高度的底部,并且是 full-width。导航正上方有一个按钮(实际上是带有点击识别器的自定义视图),用于隐藏和显示它;隐藏导航时,按钮位于主屏幕底部,显示导航时,按钮位于导航栏顶部的正上方。

问题是导航栏似乎拦截了按钮底部大约 10 个点的触摸。这是为什么?

添加 child 的代码如下所示:

UIViewController *root = [[[UIViewController alloc]init]autorelease]; //some VC
UINavigationController *nav = [[[UINavigationController alloc]initWithRootViewController:root]autorelease];
[self addChildViewController:nav];
CGRect rect = self.view.frame;
CGFloat height = 500;
nav.view.frame = CGRectMake(0, rect.size.height - height, rect.size.width, height);
[self.view addSubview:nav.view];
[nav didMoveToParentViewController:self];

//Now the button
UIView *view = [[[UIView alloc]initWithFrame:CGRectZero]autorelease];
view.backgroundColor = [UIColor greenColor];
[self.view addSubview:view];
view.frame = CGRectMake(0, rect.size.height - 500 - 40, rect.size.width, 40);
UITapGestureRecognizer *recog = [[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(onToggleSplit)]autorelease];
[view addGestureRecognizer:recog];

onToggleSplit 动画上下导航。当它启动时,点击 "button" 底部的 10 个左右的点什么都不做。我尝试在我的自定义 "button" 视图上覆盖 touchesBegan,但它甚至没有被调用。

如果我为 child VC 使用常规 UIViewController(或其子类),按钮会按预期响应。

这个问题已经被询问和回答 here。基本上,iOS 上的控件具有 "slop zones" 旨在允许用户草率的触摸准确性。我将提交一个错误,说明它不应该超出控件的视图控制器的边界。

更新:归档为雷达 19504573。

更新2:我的雷达被标记为8088542的副本,已打开。另外,我的案例有点简单(一个视图就在导航栏的顶部),所以我能够克服这个问题。我覆盖了 hitTest:withEvent: 并注意到当点击发生时,它会被调用两次。首先,触摸坐标是您期望的,调用 super returns 是您期望的视图。第二个在事件上具有相同的 timestamp 值,但 y 坐标更高(在屏幕上更低)并且 super return 是导航栏。所以:

  • Subclass UIView 并添加一个 属性 viewToWatch.
  • 在我的主视图控制器 nib/storyboard 中,将视图 class 设置为我的子视图。
  • 在我的主视图控制器 viewDidLoad 中,抓取视图,投射它,然后将其 viewToWatch 设置为触摸事件被窃取的视图。
  • 在自定义视图中,定义两个私有属性:NSTimeInterval lastTimestampBOOL isInView
  • 覆盖 hitTest:withEvent:。如果调用 super 产生 viewToWatch,请将 lastTimestamp 设置为事件的标记,将 isInView 设置为 YES。否则,如果 super return 是导航栏,如果事件的标记匹配并且 isInView 仍然是 YES,则重置属性和 return viewToWatch .

到目前为止一切正常。