如何单击透明UIView后面的按钮?

Sea*_*ess 171 iphone cocoa-touch objective-c ipad ios

假设我们有一个带有一个子视图的视图控制器.子视图占据屏幕中心,四周边距为100 px.然后我们在子视图中添加一些小东西来点击.我们只使用子视图来利用新帧(子视图中的x = 0,y = 0实际上是父视图中的100,100).

然后,假设我们在子视图后面有一些东西,比如菜单.我希望用户能够在子视图中选择任何"小东西",但如果没有任何东西,我希望触摸通过它(因为背景是清晰的)到它后面的按钮.

我怎样才能做到这一点?它看起来像touchesBegan,但按钮不起作用.

Joh*_*hen 302

为容器创建自定义视图并覆盖pointInside:message,当该点不在符合条件的子视图中时返回false,如下所示:

迅速:

class PassThroughView: UIView {
    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        for subview in subviews {
            if !subview.isHidden && subview.isUserInteractionEnabled && subview.point(inside: convert(point, to: subview), with: event) {
                return true
            }
        }
        return false
    }
}
Run Code Online (Sandbox Code Playgroud)

目标C:

@interface PassthroughView : UIView
@end

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

将此视图用作容器将允许其任何子项接收触摸,但视图本身对事件是透明的.

  • 有趣.我需要更多地深入到响应者链中. (4认同)
  • 不幸的是,这个技巧不适用于tabBarController,无法更改视图.有人想让这个视图对事件透明吗? (2认同)
  • 我做了一个快速的版本:也许你可以把它包括在可见性的答案中https://gist.github.com/eyeballz/17945454447c7ae766cb (2认同)

akw*_*akw 101

我也用

myView.userInteractionEnabled = NO;
Run Code Online (Sandbox Code Playgroud)

不需要子类.工作良好.

  • 这也将禁用任何子视图的用户交互 (73认同)

jac*_*ash 19

来自Apple:

事件转发是某些应用程序使用的技术.您可以通过调用另一个响应程序对象的事件处理方法来转发触摸事件.虽然这可能是一种有效的技术,但您应谨慎使用.UIKit框架的类不是设计用于接收未绑定到它们的触摸....如果要有条件地将触摸转发给应用程序中的其他响应者,则所有这些响应者都应该是您自己的UIView子类的实例.

苹果最佳实践:

不要在响应者链中明确发送事件(通过nextResponder); 相反,调用超类实现并让UIKit处理响应者链遍历.

相反,你可以覆盖:

-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
Run Code Online (Sandbox Code Playgroud)

在您的UIView子类中,如果您希望将响应发送到响应程序链(IE到视图后面的视图,其中没有任何内容),则返回NO.


Jef*_*eff 7

更简单的方法是在接口构建器中"取消选中"用户交互."如果你使用故事板"

在此输入图像描述

  • 正如其他人在类似的答案中指出的那样,这在这种情况下没有用,因为它也会在底层视图中禁用触摸事件.换句话说:无论您是否启用此设置,都无法轻触该视图下方的按钮. (4认同)

Tod*_*ham 6

在John发布的内容的基础上,这里有一个示例,它允许触摸事件通过除按钮之外的视图的所有子视图:

-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    // Allow buttons to receive press events.  All other views will get ignored
    for( id foundView in self.subviews )
    {
        if( [foundView isKindOfClass:[UIButton class]] )
        {
            UIButton *foundButton = foundView;

            if( foundButton.isEnabled  &&  !foundButton.hidden &&  [foundButton pointInside:[self convertPoint:point toView:foundButton] withEvent:event] )
                return YES;
        }        
    }
    return NO;
}
Run Code Online (Sandbox Code Playgroud)


Seg*_*gev 6

最近我写了一个课程,这将帮助我.将其用作UIButtonUIView将传递在透明像素上执行的触摸事件的自定义类.

此解决方案比接受的答案稍好一些,因为您仍然可以单击UIButton半透明下的UIView,而非透明部分UIView仍然会响应触摸事件.

GIF

正如你在GIF中看到的那样,长颈鹿按钮是一个简单的矩形,但透明区域上的触摸事件会传递到UIButton下面的黄色.

链接到课堂

  • 虽然此解决方案可能有效,但最好将解决方案的相关部分放在答案中。 (2认同)

Pak*_*toV 6

最高投票的解决方案对我来说并不完全有效,我想这是因为我在层次结构中有一个 TabBarController(正如其中一条评论指出的那样)它实际上是将触摸传递到 UI 的某些部分,但它弄乱了我的tableView 拦截触摸事件的能力,它最终在视图中覆盖了hitTest我想忽略触摸并让该视图的子视图处理它们

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
    UIView *view = [super hitTest:point withEvent:event];
    if (view == self) {
        return nil; //avoid delivering touch events to the container view (self)
    }
    else{
        return view; //the subviews will still receive touch events
    }
}
Run Code Online (Sandbox Code Playgroud)