禁用UIView背景上的触摸,以便可以单击较低视图上的按钮

ave*_*dev 28 iphone objective-c

基本上,这是我的视图层次结构(如果这很难读,我会道歉......我是新来的,所以发布的建议很乐意接受)


--AppControls.xib
-------(UIView)ControlsView
-----------------(UIView)TopBar
------------- ---- -------------- btn1,btn2,btn3
----------------- UIView)BottomBar
------- ---------- -------------- slider1 btn1,btn2
--PageContent.xib
----------------- (UIView)ContentView
----------------- -------------- btn1,btn2,btn3
---------- ------- --------------(UIImageView)FullPageImage


我的情况是,我想隐藏和显示控件,当点击PageContent上的任何地方而不是按钮并且控件显示时,就像iPhone视频播放器一样.但是,当显示控件时,我仍然希望能够单击PageContent上的按钮.

除了最后一点,我完成了所有这些工作.当控件显示控件的背景时,接收触摸事件而不是下面的视图.在ControlsView上关闭用户交互会在其所有子节点上关闭它.

我已经尝试在我的ControlsView子类上重写HitTest,如下所示,我在类似的帖子中找到了:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
UIView *hitView = nil;
NSArray *subviews = [self subviews];
int subviewCount = [subviews count];
for (int subviewIndex = 0; !hitView && subviewIndex < subviewCount; subviewIndex++){
hitView = [[subviews objectAtIndex:subviewIndex] hitTest:point withEvent:event];
}   
return hitView;
}
Run Code Online (Sandbox Code Playgroud)

但是,此时我的滑块不起作用,大多数其他按钮也不起作用,事实上,事情开始变得怪异.

所以我的问题很简单:如何让视图的所有子视图都有触摸事件,而超级视图的背景是不可点击的,下面视图上的按钮可以接收触摸事件.

谢谢!

Ben*_*tto 69

你很亲密 不要覆盖-hitTest:withEvent:.到调用时,事件调度程序已经确定您的层次结构的子树拥有该事件,并且不会查找其他地方.相反,覆盖-pointInside:withEvent:,在事件处理管道中先前调用.这就是系统如何询问"嘿视图,你的层次结构中的任何人在此时对事件做出响应吗?".如果您拒绝,则事件处理将在可见堆栈中继续进行.

根据文档,默认实现只是检查该点是否在视图的边界内.

当您的任何子视图处于该坐标时,您的策略是说"是",但当触摸将触及背景时说"不".

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    for (UIView * view in [self subviews]) {
        if (view.userInteractionEnabled && [view pointInside:[self convertPoint:point toView:view] withEvent:event]) {
            return YES;
        }
    }
    return NO;
}
Run Code Online (Sandbox Code Playgroud)

  • 当然.:)我没有看到显示层次结构如此完全地在SO上建模,但看起来这样很有用.仅供参考,这是一个有趣的调试技巧:在断点处停止的gdb中,尝试运行`po [myView recursiveDescription]`.它从那一点向下转储整个层次结构. (6认同)

Rom*_*zak 5

感谢@Ben Zutto,Swift 3解决方案:

override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
    for view in self.subviews {
        if view.isUserInteractionEnabled, view.point(inside: self.convert(point, to: view), with: event) {
            return true
        }
    }

    return false
}
Run Code Online (Sandbox Code Playgroud)