设置:我有父视图A.它有一个子视图B. B部分位于A的边界内,但部分位于外部(A有clipsToBounds = false)。我已将UITapGestureRecognizer(UITGR)附加到B。
观察:当我点击B区域内的B部分时,UITGR会激活。当我点击超出A界限的B部分时,UITGR不会触发。
预期/问题:当我点击超出A界限的B部分时,如何使UITGR点火?
答案 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)
}