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

时间:2010-08-06 20:37:39

标签: 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;
}

然而,此时我的滑块不起作用,大多数其他按钮也没有用,而且真的,事情开始变得怪异。

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

谢谢!

4 个答案:

答案 0 :(得分:66)

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

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

您的策略是当您的任何子视图位于该坐标时说“是”,但当触摸将触及背景时说“不”。

- (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;
}

答案 1 :(得分:3)

感谢@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
}

答案 2 :(得分:1)

另一种方法可能是在其他所有内容后面放置一个不可见的全屏按钮,并在被击中时采取适当的行动。

答案 3 :(得分:1)

Ben的回答略有不同,处理与父母之外的孩子。 如果 clipChildren 为YES,那么对于主控制之外但在某个子节点内的点,这不会返回YES。 如果 clipChildren 为NO,则与Ben的相同。

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    BOOL clipChildren = YES;

    if (!clipChildren || [super pointInside:point withEvent:event]) {
        for (UIView * view in [self subviews]) {
            if (view.userInteractionEnabled && [view pointInside:[self convertPoint:point toView:view] withEvent:event]) {
                return YES;
            }
        }
    }
    return NO;
}