VC 容器中 UINavigationController 的点击区域问题 [英] Tap region issues with UINavigationController in VC containment
问题描述
我有一个 iOS 应用,我在其中添加了一个 UINavigationController
作为主屏幕的子视图控制器.它是垂直排列的,因此导航控制器占据主视图高度的底部并且是全宽的.有一个按钮(实际上是一个带有点击识别器的自定义视图)位于导航的正上方,用于隐藏和显示它;隐藏导航时,按钮位于主屏幕底部,显示导航时,按钮位于导航栏顶部的正上方.
I have an iOS app in which I add a UINavigationController
as a child view controller to the main screen. It's arranged vertically, so that the nav controller takes up a bottom part of the main view's height and is full-width. There is a button (actually a custom view with a tap recognizer) that sits right above the nav that is used to hide and show it; when the nav is hidden, the button is at the bottom of the main screen, and when the nav is shown the button is right above the top of the nav bar.
问题在于导航栏似乎拦截了按钮底部 10 点左右的触摸.这是为什么?
The issue is that the navigation bar appears to intercept touches on the bottom 10 points or so of the button. Why is this?
添加孩子的代码如下所示:
The code to add the child looks like this:
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
向上和向下动画导航.当它启动时,点击按钮"的底部 10 个点左右什么都不做.我尝试在我的自定义按钮"视图上覆盖 touchesBegan
,但它甚至没有被调用.
onToggleSplit
animates the nav up and down. When it's up, taps on the bottom 10 points or so of the "button" do nothing. I tried overriding touchesBegan
on my custom "button" view, and that doesn't even get called.
如果我为子 VC 使用常规的 UIViewController
(或其子类),按钮会按预期响应.
If I use a regular UIViewController
(or a subclass thereof) for the child VC, the button responds as expected.
推荐答案
此问题已被问及回答 此处.基本上,iOS 上的控件具有倾斜区域",旨在允许用户进行草率的触摸准确性.我将提交一个关于这不应该超出控件视图控制器边界的错误.
This has been asked and answered here. Basically, controls on iOS have "slop zones" designed to allow sloppy touch accuracy on the part of the user. I'm going to file a bug about how this shouldn't reach outside the control's view controller's bounds.
更新:作为雷达 19504573 提交.
Update: filed as radar 19504573.
更新 2:我的雷达被标记为 8088542 的副本,这是打开的.此外,我的案例有点简单(导航栏顶部的一个视图),所以我能够克服这个问题.我覆盖了 hitTest:withEvent:
并注意到当点击发生时,它会被调用两次.首先,触摸坐标是你期望的,调用 super
返回你期望的视图.第二个事件具有相同的 timestamp
值,但 y 坐标更高(在屏幕上更低)并且 super
返回导航栏.所以:
Update 2: my radar has been marked as a duplicate of 8088542, which is open. Also, my case is somewhat simple (one view right on top of a navigation bar), so I was able to overcome the issue. I overrode hitTest:withEvent:
and noticed that when a tap happens, it gets called twice. On the first, the touch coordinates are what you expect, and calling super
returns the view you expect. The second has the same timestamp
value on the event, but the y coordinate is higher (lower on the screen) and super
returns the nav bar. So:
- 子类
UIView
并添加属性viewToWatch
. - 在我的主视图控制器的笔尖/故事板中,将视图类设置为我的子视图.
- 在我的主视图控制器的
viewDidLoad
中,抓取视图,将其投射,并将其viewToWatch
设置为正在窃取触摸事件的视图. - 在自定义视图中,定义两个私有属性:
NSTimeInterval lastTimestamp
和BOOL isInView
. - 覆盖
hitTest:withEvent:
.如果调用 super 产生viewToWatch
,请将lastTimestamp
设置为事件的标记,并将isInView
设置为YES
.否则,如果super
返回导航栏,如果事件的标记匹配并且isInView
仍然是YES
,则重置两个属性并返回viewToWatch
.
- Subclass
UIView
and add a propertyviewToWatch
. - In my main view controller's nib/storyboard, set the view class to my subview.
- In my main view controller's
viewDidLoad
, grab the view, cast it, and set itsviewToWatch
to the view whose touch events are being filched. - In the custom view, define two private properties:
NSTimeInterval lastTimestamp
andBOOL isInView
. - Override
hitTest:withEvent:
. If calling super yieldsviewToWatch
, set thelastTimestamp
to the event's stamp andisInView
toYES
. Otherwise, ifsuper
returns a nav bar, if the event's stamp matches andisInView
is stillYES
, reset both properties and returnviewToWatch
.
到目前为止一切正常.
这篇关于VC 容器中 UINavigationController 的点击区域问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!