设置:我有父视图 A。它有一个子视图 B。B 部分位于 A 的边界内,但部分位于 A 的边界之外(A 的 clipsToBounds=false)。我已将 UITapGestureRecognizer (UITGR) 附加到 B.
观察到:当我点击 A 范围内的 B 部分时,UITGR 触发 OK。当我点击 A 范围之外的 B 部分时,UITGR 不会触发。
预期/问题:当我点击 A 边界之外的 B 部分时,如何使 UITGR 触发?
设置:我有父视图 A。它有一个子视图 B。B 部分位于 A 的边界内,但部分位于 A 的边界之外(A 的 clipsToBounds=false)。我已将 UITapGestureRecognizer (UITGR) 附加到 B.
观察到:当我点击 A 范围内的 B 部分时,UITGR 触发 OK。当我点击 A 范围之外的 B 部分时,UITGR 不会触发。
预期/问题:当我点击 A 边界之外的 B 部分时,如何使 UITGR 触发?
这句话将回答你关于它为什么会这样的问题:
触摸事件。窗口对象使用命中测试和响应者链来找到接收触摸事件的视图。在命中测试中,窗口在视图层次结构的最顶层视图上调用 hitTest:withEvent:;此方法通过在视图层次结构中返回 YES 的每个视图上递归调用 pointInside:withEvent: 来继续,沿着层次结构向下进行,直到找到发生触摸的子视图。该视图成为命中测试视图。(来源)
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];
}
然后你将这个类用于你的父视图。
(几周前我在 SO 的一篇帖子中找到了这段代码,但我似乎再也找不到它了;所以只是从我的项目中复制了它)。
更新@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)
}
您必须为视图 A 编写自己的 hittest 函数。
还要看这个问题:UITapGestureRecognizer not trigger in deep view hiearchy