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

问题描述 投票:5回答:3

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

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

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

cocoa-touch uiview uigesturerecognizer
3个回答
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.的帖子中找到了这段代码,但我似乎无法再找到它了;所以只是从我的项目中复制它)。


0
投票

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

还要看看这个问题:UITapGestureRecognizer not triggered in deep view hiearchy


0
投票

更新@sergio对Swift 4.2的回答:

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)
}
© www.soinside.com 2019 - 2024. All rights reserved.