37

我有 3 个 UIView,位于一个大的 uiview 之上。我想知道用户是否触摸了顶部而不关心其他的。我将在第二个 UIView 中有几个按钮,在第三个 UIView 中有一个 UITable。

问题是我在第一个视图上打开了 userInteractionEngabled 并且有效,但是即使我将其关闭,所有其他视图也以相同的方式响应。如果我在 self.view 上禁用 userInteractionEnabled,他们都没有响应。我也无法检测到 touchesBegan 委托方法中触摸了哪个视图。

我的代码:

UIView *aView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 150)];
aView = userInteractionEnabled = YES;
[self.view addSubview:aView];

UIView *bView = [[UIView alloc] initWithFrame:CGRectMake(0, 150, 320, 50)];
bView.userInteractionEnabled = NO;
[self.view addSubview:bView];

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
//This gets called for a touch anywhere
}
4

8 回答 8

64

为了检查另一个视图中的某个视图是否被触摸,您可以使用 hitTest。

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;

在您自定义的 touchesBegan 实现中,检查 touches 集中的每个触摸。可以使用 hitTest 方法获得点

- (CGPoint)locationInView:(UIView *)view;

方法,其中视图是您的超级视图(包含其他视图的视图)。

编辑:这是一个快速的自定义实现:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 
    CGPoint locationPoint = [[touches anyObject] locationInView:self];
    UIView* viewYouWishToObtain = [self hitTest:locationPoint withEvent:event];
}

我希望这会有所帮助,保罗

于 2010-05-08T07:15:50.993 回答
30

在我的情况下,hitTest 没有返回我想要找到的 UIView。但是下面的代码效果更好:

    CGPoint locationPoint = [[touches anyObject] locationInView:self.view];
    CGPoint viewPoint = [myImage convertPoint:locationPoint fromView:self.view];
    if ([myImage pointInside:viewPoint withEvent:event]) {
       // do something
    }
于 2011-10-05T22:19:50.300 回答
16

SWIFT代码:

 override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        if let touch = touches.first {
            if touch.view == self.view {
                self.hideInView()
            } else {
                return
            }

        }
    }
于 2016-06-16T09:43:05.197 回答
15

这也可以通过以下方式完成。

首先在你关心的视图中找到触摸的位置:

CGPoint location = [touches.anyObject locationInView:viewYouCareAbout];

然后查看该点是否在视图的范围内:

BOOL withinBounds = CGRectContainsPoint(viewYouCareAbout.bounds, location);

然后,如果它在界限内,请执行您的操作。

这可以通过一个语句来完成,例如,可以直接在 if 语句中使用:

CGRectContainsPoint(viewYouCareAbout.bounds, [touches.anyObject locationInView:viewYouCareAbout])
于 2013-09-04T16:23:59.257 回答
8

touchesBegan检查触摸的视图是否是您想要的视图,当我尝试确定用户是否触摸了特定的ImageView时,为我解决了这个问题。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    if ([touch view] ==  imageView ) {
        ... your code to handle the touch
    }
    ...

如果您调整视图尺寸的内容,请确保相应地更改视图大小,否则即使在视图中存在此类内容的区域,它也会识别触摸事件。就我而言,当我尝试使用UIViewContentModeScaleAspectFit保持图像比例时,尽管在“空白”区域中也根据需要调整了图像,但触摸事件也被捕获。

于 2013-02-20T09:55:04.100 回答
7

我的快速版本检查触摸发生在 infoView 中:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    guard let touch = touches.first, infoView.bounds.contains(touch.location(in: infoView))  else { return }
    print("touchesBegan") // Replace by your own code
} // touchesBegan
于 2018-04-09T18:47:57.333 回答
0

这对我有用:

func respondToGesture(gesture: UIGestureRecognizer) {
    let containsPoint = CGRectContainsPoint(targetView.bounds, gesture.locationInView(targetView))
}
于 2016-06-27T06:27:19.353 回答
0

当您的应用程序接收到一个触摸事件时,将启动一个命中测试过程以确定哪个视图应该接收该事件。该过程从视图层次结构的根开始,通常是应用程序的窗口,并按从前到后的顺序搜索子视图,直到找到触摸下的最前面的视图。该视图成为命中测试视图并接收触摸事件。此过程中涉及的每个视图首先测试事件位置是否在其范围内。只有在测试成功后,视图才会将事件传递给子视图以进行进一步的命中测试。因此,如果您的视图处于触摸状态但位于其父视图边界之外,则父视图将无法测试事件位置并且不会将触摸事件传递给您的视图。

解决此问题的一种方法是修改视图层次结构的布局,以便您的视图位于其父视图的边界内。如果由于某些原因必须维护现有布局,您可以更改父视图的命中测试行为,以便它不会忽略触摸事件。这可以通过覆盖父视图类的 -(UIView *)hitTest:withEvent: 方法来完成

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {

    // Convert the point to the target view's coordinate system.
    // The target view isn't necessarily the immediate subview
    CGPoint pointForTargetView = [self.targetView convertPoint:point fromView:self];

    if (CGRectContainsPoint(self.targetView.bounds, pointForTargetView)) {

        // The target view may have its view hierarchy,
        // so call its hitTest method to return the right hit-test view
        return [self.targetView hitTest:pointForTargetView withEvent:event];
    }

    return [super hitTest:point withEvent:event]; }

此问题的其他可能原因包括:

您的视图或其任何父视图的 userInteractionEnabled 属性设置为 NO。应用程序调用了它的 beginIgnoringInteractionEvents 方法,而没有对其 endIgnoringInteractionEvents 方法的匹配调用。您应该确保 userInteractionEnabled 属性设置为 YES,并且如果您希望视图具有交互性,应用程序不会忽略用户事件。

如果您的视图在动画期间没有收到触摸事件,那是因为 UIView 的动画方法通常会在动画进行时禁用触摸事件。您可以通过在启动 UIView 动画时适当地配置 UIViewAnimationOptionAllowUserInteraction 选项来更改该行为。

另一种解决方案是

在视图中添加您自己的自定义实现

class CustomView: YourParentView {

    override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {

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


extension UIView {

    func overlapHitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {

        // 1
        if !self.isUserInteractionEnabled || self.isHidden || self.alpha == 0 {

            return nil
        }

        // 2
        var hitView: UIView? = self
        if !self.point(inside: point, with: event) {

            if self.clipsToBounds {

                return nil
            } else {

                hitView = nil
            }
        }

        // 3
        for subview in self.subviews.reversed() {

            let insideSubview = self.convert(point, to: subview)
            if let sview = subview.overlapHitTest(point: insideSubview, withEvent: event) {
                return sview
            }
        }
        return hitView
    }
}
于 2019-05-01T16:35:27.807 回答