Swift: 在另一个UIView下方的UIView上使用hitTest

4

我在RedOrGreenUIView上方放了一个TransparentUIView。TransparentUIView上附加了一个UILongPressGestureRecognizer手势。当用户开始长按它时,我会检查这个LongPressGesture的.Changed状态,并执行以下hitTest操作:

var p:CGPoint = rec.locationInView(self.view)
var selectedView = view.hitTest(p, withEvent: nil)
if selectedView != nil {
   if selectedView == TransparentUIView {
       println("TransparentUIView is being touched")
   }
}

我已经成功选中了TransparentView。但是我需要同时对RedOrGreenUIView进行hitTest,而它在TransparentUIView下面。我无法理解如何实现这个目标,请帮忙。

4个回答

13
为您的容器创建一个自定义视图,并重写pointInside:消息,以便当点不在合格的子视图内时返回NO,如下所示:
@interface PassthroughView : UIView
@end

@implementation PassthroughView
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    for (UIView *view in self.subviews) {
        if (!view.hidden && view.alpha > 0 && view.userInteractionEnabled && [view pointInside:[self convertPoint:point toView:view] withEvent:event])
            return YES;
    }
    return NO;
}
@end

Swift版本

class PassThroughView: UIView {

     override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {
            for subview in subviews as [UIView] {
                if !subview.hidden && subview.alpha > 0 && subview.userInteractionEnabled && subview.pointInside(convertPoint(point, toView: subview), withEvent: event) {
                    return true
                }
            }
            return false
        }
    }

1
通过UIView,有一个包含网格按钮的stackView,按钮之间的间隙是stackView间距。 stackView间距不会将触摸传递到下面的视图。请问如何通过stackView间距传递触摸? - theMouse

3

Swift 4版本:

 override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        for subview in YourView.subviews as [UIView] {

            if !subview.isHidden && subview.alpha > 0 && subview.isUserInteractionEnabled && subview.point(inside:point, with: event) {
                return true
            }
        }

    return false
 }

当你子类化UIView时,请重写上述方法。 - byJeevan

1

我目前正在为iOS应用程序开发透明的帮助覆盖层,并且自己正在寻找一个好的答案。

我找不到什么有用的东西,所以决定再深入研究一下。苹果关于hitTest的文档说,它不包括透明度小于0.1、隐藏或userInteractionEnabled为false的视图。

最后一个给了我一个想法,这似乎是一个相当不错的解决方案。

请尝试以下方法(我仍需要进一步测试,但它似乎还可以):

var p:CGPoint = rec.locationInView(self.view)

TransparentUIView.isUserInteractionEnabled = false

var selectedView = view.hitTest(p, withEvent: nil)

TransparentUIView.isUserInteractionEnabled = true

if selectedView != nil {
    if selectedView == TransparentUIView {
        println("TransparentUIView is being touched")
    }
}

1
如果一个UIView接收到了触摸事件,其他在它下面的UIView就不会收到。因此,你可以有一个中心类来将触摸事件传递给你的两个UIView对象,或者第一个UIView(即在顶部的那个)将其UITouch对象传递给下面的UIView并进行hitTest。

1
另外,我可以建议使用方法交换来获取触摸并将它们发布到各个地方,但是让我们先学会走路再跑步,好吗? :) - Shamas S
我喜欢第二个选项。您能否告诉我如何将UITouch对象传递到另一个视图?我在谷歌上找到的所有帮助都是ObjC的,而我不理解。 - Kashif
1
在您的UIView中实现touchesBegan、touchesMoved和touchesEnded方法。这将为您提供此视图中的UITouch对象。一旦获取到它们,您可以将它们用于hitTest或将这些对象发送到下面的视图。为此,在下面的视图中编写一个函数,并将UITouch对象作为参数传递。 - Shamas S

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接