如何在父视图部分剪切的子视图上触发UITapGestureRecognizer?

时间:2012-05-07 04:07:22

标签: cocoa-touch uiview uigesturerecognizer

设置:我有父视图A.它有一个子视图B. B部分位于A的边界内,但部分位于外部(A有clipsToBounds = false)。我已将UITapGestureRecognizer(UITGR)附加到B。

观察:当我点击B区域内的B部分时,UITGR会激活。当我点击超出A界限的B部分时,UITGR不会触发。

预期/问题:当我点击超出A界限的B部分时,如何使UITGR点火?

3 个答案:

答案 0 :(得分:7)

这句话将回答你关于为什么它的行为的问题:

  

触摸事件。窗口对象使用命中测试和响应者链来查找接收触摸事件的视图。在命中测试中,窗口在视图层次结构的最顶层视图上调用hitTest:withEvent:此方法通过在视图层次结构中返回YES的每个视图上递归调用pointInside:withEvent:继续执行,继续向下移动层次结构,直到找到触摸发生在其边界内的子视图。该视图成为热门测试视图。   (source

一种解决方法是使用UITapInSubviewsView的以下定义创建您自己的hitTest

(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    NSEnumerator *reverseE = [self.subviews reverseObjectEnumerator];
    UIView *iSubView;
    while ((iSubView = [reverseE nextObject])) {

        UIView *viewWasHit = [iSubView hitTest:[self convertPoint:point toView:iSubView] withEvent:event];
        if(viewWasHit)
           return viewWasHit;
     }
     return [super hitTest:point withEvent:event];
}

然后将此类用于父视图。

(几周前我在S.O.的帖子中找到了这段代码,但我似乎无法再找到它了;所以只是从我的项目中复制了它。)

答案 1 :(得分:0)

你必须为视图A编写自己的hittest函数。

另请看这个问题:UITapGestureRecognizer not triggered in deep view hiearchy

答案 2 :(得分:0)

更新 Swift 4.2 @sergio的答案:

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    let reversedSubviews = subviews.reversed()
    let hitSubview = reversedSubviews
        .first(where: { $0.hitTest(convert(point, to: $0), with: event) != nil })
    if hitSubview != nil {
        return hitSubview
    }

    return super.hitTest(point, with: event)
}