通过触摸到下面的UIViews

时间:2012-01-26 22:05:46

标签: iphone ios uiview uiimageview uitapgesturerecognizer

我有一个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:touchesCancelled:方法,并在包含UIImageView的视图中调用了它们的超级实现。使用上面的代码,永远不会调用touchesCancelled:,并始终调用touchesBegan:

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

更新

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

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

我认为操作系统首先执行hitTest,因为View2在前面,所以应该获得所有的触摸,除非为View2将userInteractions设置为NO,否则它们永远不会传递给View3,在这种情况下,imageView1也会被阻止接收触动。它是如何工作的,View2是否有办法通过它接触到View3?

6 个答案:

答案 0 :(得分:89)

我认为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查询其视图层次结构的其余部分,寻找命中。

答案 1 :(得分:57)

ViewStoryboard和...

中选择XIB

enter image description here

或在Swift中

view.isUserInteractionEnabled = false

答案 2 :(得分:5)

查看UIGestureRecognizerDelegate Protocol。具体而言,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;
    }
}

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

答案 3 :(得分:2)

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

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

- (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 touchesEndedtouchesCancelled完全相同。

答案 4 :(得分:1)

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

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 for ImagePickerViewController.cameraOverlay中使用它,以便用户在拍摄新照片时能够发表评论

答案 5 :(得分:0)

// this is due to userInteractionEnabled deficiency: the flag stops traversal of subviews
@objc(YourObjcPrefixHereForXibAndStoryboardUseViewTransparentToTouch)
open class ViewTransparentToTouch: UIView
{
public var daisyView: UIView?
override open func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    let hitView = super.hitTest(point, with: event)
    if hitView === self {
        return daisyView
    }
    return hitView // childView
}
}