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 lastTimestamp
和BOOL isInView
。
- 覆盖
hitTest:withEvent:
。如果调用 super 产生 viewToWatch
,请将 lastTimestamp
设置为事件的标记,将 isInView
设置为 YES
。否则,如果 super
return 是导航栏,如果事件的标记匹配并且 isInView
仍然是 YES
,则重置属性和 return viewToWatch
.
到目前为止一切正常。
我有一个 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 lastTimestamp
和BOOL isInView
。 - 覆盖
hitTest:withEvent:
。如果调用 super 产生viewToWatch
,请将lastTimestamp
设置为事件的标记,将isInView
设置为YES
。否则,如果super
return 是导航栏,如果事件的标记匹配并且isInView
仍然是YES
,则重置属性和 returnviewToWatch
.
到目前为止一切正常。