通过触摸到下面的UIViews

问题描述 投票:61回答:6

我有一个带有4个按钮的UIView和按钮视图顶部的另一个UIView。最顶层的视图包含一个带有UIImageViewUITapGestureRecognizer

我试图创建的行为是,当用户点击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:总是被调用。

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

UPDATE

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

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

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

iphone ios uiview uiimageview uitapgesturerecognizer
6个回答
90
投票

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


59
投票

ViewStoryboard中选择你的XIB和......



或者在斯威夫特

view.isUserInteractionEnabled = false

6
投票

看看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;
    }
}

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


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


2
投票

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


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
}
}
© www.soinside.com 2019 - 2024. All rights reserved.