73

我有一个UIView带有 4 个按钮的按钮,另一个UIView在按钮视图的顶部。最上面的视图包含一个UIImageView带有一个UITapGestureRecognizer的。

我试图创建的行为是,当用户点击UIImageView它时,它会在屏幕右下角变小和动画变大之间切换。当它很大时,我希望禁用底部视图上的按钮,当它很小并且在右下角时,我希望将触摸传递给按钮并使它们正常工作。我快到了,但除非我禁用UserInteractions顶视图,否则我无法让触摸传递到按钮。

initWithFrame:的顶视图中有这个:

// Add a gesture recognizer to the image view
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(imageTapped:)];
tapGestureRecognizer.cancelsTouchesInView = NO;
[imageView addGestureRecognizer:tapGestureRecognizer];
[tapGestureRecognizer release];

我这是我的imageTapped:方法:

- (void) imageTapped:(UITapGestureRecognizer *) gestureRecognizer {
    // Toggle between expanding and contracting the image
    if (expanded) {
        [self contractAnimated:YES];
        expanded = NO;
        gestureRecognizer.cancelsTouchesInView = NO;
        self.userInteractionEnabled = NO;
        self.exclusiveTouch = NO;
    }
    else {
        [self expandAnimated:YES];
        expanded = YES;
        gestureRecognizer.cancelsTouchesInView = NO;
        self.userInteractionEnabled = YES;
        self.exclusiveTouch = YES;
    }
}

使用上面的代码,当图像很大时,按钮处于非活动状态,当我触摸图像时,它会缩小并且按钮变为活动状态。但是,小图像不会收到触摸,因此不会扩展。

如果我self.userInteractionEnabled = YES在这两种情况下都进行了设置,那么在触摸时图像会展开和收缩,但按钮永远不会收到触摸并且就像被禁用一样。

是否有办法让图像在触摸时展开和收缩,但如果图像处于收缩状态,下面的按钮只能接收触摸?我在这里做一些愚蠢的事情并且错过了一些明显的事情吗?

我要让这个工作变得非常疯狂,所以任何帮助都将不胜感激,

戴夫

更新:

为了进一步测试,我覆盖了touchesBegan:andtouchesCancelled:方法,并在包含 UIImageView 的视图上调用了它们的超级实现。使用上面的代码,touchesCancelled:永远不会调用 并且touchesBegan:总是调用 。

所以看起来视图正在被触摸,它们只是没有传递到下面的视图。

更新

这是因为响应者链的工作方式吗?我的视图层次结构如下所示:

VC - View1
     -View2
      -imageView1 (has tapGestureRecogniser)
      -imageView2
     -View3
      -button1
      -button2

我认为操作系统首先执行 hitTest,因为 View2 在前面,所以应该得到所有的触摸,并且这些触摸永远不会传递给 View3,除非 View2 的 userInteractions 设置为 NO,在这种情况下,imageView1 也被阻止接收触摸。这是它的工作原理吗? View2 有没有办法通过它对 View3 的接触?

4

5 回答 5

95

UIGestureRecognizer 是我认为的红鲱鱼。最后为了解决这个问题,我覆盖了我的pointInside:withEvent:方法UIView:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    BOOL pointInside = NO;

    if (CGRectContainsPoint(imageView.frame, point) || expanded) pointInside = YES;

    return pointInside;
}

如果您触摸 imageView 或设置了它的扩展标志,这将导致视图捕获所有触摸。如果它没有展开,那么只有当它们在 imageView 上时才捕获触摸。

通过返回 NO,顶级 VC 的 View 查询其视图层次结构的其余部分以寻找命中。

于 2012-01-27T09:59:47.360 回答
69

选择您View的输入StoryboardXIB...


在此处输入图像描述


或者在斯威夫特

view.isUserInteractionEnabled = false
于 2015-06-22T18:27:15.293 回答
6

查看UIGestureRecognizerDelegate 协议。具体来说,gestureRecognizer:shouldReceiveTouch:

你会想让每UIGestureRecognizer一个都成为你的属性UIViewController

// .h
@property (nonatomic, strong) UITapGestureRecognizer *lowerTap;

// .m
@synthesize lowerTap;

// When you are adding the gesture recognizer to the image view
self.lowerTap = tapGestureRecognizer

确保你让你UIViewController的代表,

[self.lowerTap setDelegate: self];

然后,你会有这样的东西,

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    if (expanded && gestureRecognizer == self.lowerTap) {    
        return NO;
    }
    else {
        return YES;
    }
}

当然,这不是确切的代码。但这是您要遵循的一般模式。

于 2012-01-26T22:17:00.297 回答
3

我有另一个解决方案。我有两个视图,我们称它们CustomSubView为重叠的,它们都应该得到触摸。所以我有一个视图控制器和一个自定义 UIView 类,让我们称之为ViewControllerView我在界面构建器中设置的,然后我添加了两个应该接收该视图的触摸的视图。

所以我ViewControllerView通过覆盖hitTest来拦截触摸:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    return self;
}

然后我改写了ViewControllerView

- (void)touchesBegan:(NSSet *)touches
           withEvent:(UIEvent *)event
{
    [super touchesBegan:touches withEvent:event];
    for (UIView *subview in [self.subviews reverseObjectEnumerator])
    {
        if ([subview isKindOfClass:[CustomSubView class]])
        {
            [subview touchesBegan:touches withEvent:event];
        }
    }
}

touchesMoved touchesEnded和做同样的事情touchesCancelled

于 2016-03-16T09:22:12.560 回答
3

@Magic Bullet Dave 的解决方案,但在 Swift 中

斯威夫特 3

override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
    var pointInside = false
    if commentTextField.frame.contains(point) {
        pointInside = true
    } else {
        commentTextField.resignFirstResponder()
    }
    return pointInside
}

我在我的 CameraOverlayView 中为 ImagePickerViewController.cameraOverlay 使用它,让用户能够在拍摄新照片时发表评论

于 2018-02-06T23:00:49.180 回答