作为 UIWindow 子视图添加的 UIView 不响应点击

Posted

技术标签:

【中文标题】作为 UIWindow 子视图添加的 UIView 不响应点击【英文标题】:UIView added as an UIWindow subview doesn't respond to taps 【发布时间】:2014-08-18 14:02:42 【问题描述】:

我添加了一个包含UITapGestureRecognizerUIView 作为我的关键窗口的子视图。它正确显示,但是当我点击我的视图时,不会触发目标方法。我什至尝试将手势识别器替换为UIButton,但仍然无济于事。

这是我的代码。

NotificationView.h

#import <UIKit/UIKit.h>

typedef NS_ENUM(int, NotificationKind) 
    NotificationKindActivity,
    NotificationKindReply,
;

@interface NotificationView : UIView 

    NotificationKind currentNotificationKind;



-(id)initWithMessage:(NSString*)message andColor:(UIColor*)color andKind:(NotificationKind)kind;
-(void)show;

@end

NotificationView.m

#import "NotificationView.h"

@implementation NotificationView

- (id)initWithMessage:(NSString*)message andColor:(UIColor*)color andKind:(NotificationKind)kind

    self = [super initWithFrame:CGRectMake(0, 0, CGRectGetWidth([UIScreen mainScreen].bounds), 60)];
    if (self) 
        // Initialization code
        [self setAlpha:0];
        [self setBackgroundColor:color];
        [self setUserInteractionEnabled:YES];


        currentNotificationKind = kind;

        UILabel *label = [[UILabel alloc] initWithFrame:self.bounds];
        [label setNumberOfLines:0];
        [label setFont:[UIFont fontWithName:@"Roboto-Italic" size:20]];
        [label setTextColor:[UIColor whiteColor]];
        [label setTextAlignment:NSTextAlignmentCenter];
        [label setPreferredMaxLayoutWidth:290];
        [label setText:message];
        [label setUserInteractionEnabled:YES];
        [self addSubview:label];

        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(notificationTapped)];
        [tap setNumberOfTapsRequired:1];
        [self addGestureRecognizer:tap];

        [[[UIApplication sharedApplication] keyWindow] addSubview:self];

    
    return self;


-(void)show
    [UIView animateWithDuration:0.3 animations:^

        [self setAlpha:1];

     completion:^(BOOL finished) 

        [UIView animateWithDuration:0.3 delay:3 options:UIViewAnimationOptionCurveLinear animations:^
            [self setAlpha:0];

         completion:^(BOOL finished) 
            [self removeFromSuperview];
        ];

    ];


-(void)notificationTapped

    DDLogDebug(@"Notification tapped!");



@end

【问题讨论】:

这里总猜测,但你不应该重新分配“自我”。调用 super 并且不要使用它的返回值。 你能描述一下这个通知视图是如何呈现/关闭的吗?我问是因为我很困惑为什么您首先将 alpha 设置为零,这将禁用任何触摸(此处提到 ***.com/q/8091013/3055415),并且在您的方法“显示”中,您将 alpha 设置为 1,然后返回 0,然后从超级视图。 @MattS,我相信这是子类化时的默认过程,它在其他任何地方都能正常工作...... @JustinMoser,我在收到远程通知时创建视图。我只是调用设置它的构造函数(GUI)并将其添加到键窗口。如您所见,当时的 alpha 为 0。现在,当我在视图上调用show 时,动画会在 0.3 秒内将视图 alpha 更改为 1,等待 3 秒,然后在 0.3 秒内将其 alpha 设置回 0,然后从 superview 中删除视图。它完全符合预期(动画甚至看起来不错),但是我无法点击它。 @MartinHerman 啊,我明白了!如果其他一切都正确,那么您只需要添加一点点即可。将 UIViewAnimationOptionAllowUserInteraction 添加到您的 3 秒动画块中,如下所示:[UIView animateWithDuration:0.3 delay:3 options:UIViewAnimationOptionCurveLinear|UIViewAnimationOptionAllowUserInteraction animations^... 【参考方案1】:

当这种情况发生在我身上时,通常是因为我搞砸了我的 UIView 框架。我按预期看到了所有内容,因为我的UIView 没有剪裁到边界,但我无法与任何东西交互,因为我的点击超出了UIView 的边界。

我的简单测试是更改 UIView 的背景颜色,看看它是否覆盖了我期望的区域,或者我是否以某种方式搞砸了大小/位置。

我曾经因为这个问题把头撞在墙上,挣扎了好几个小时,但我已经做了很多次了,现在只需要 5 分钟就可以解决“哦,又来了”。

编辑:

然后我会查看您的show 代码。您的调用代码不在这里,但如果我假设您只是使用您的 show 代码并且您的视图仅在屏幕上显示 3 秒,那么这就是您的问题。

正如 Justin 提到的(上面的评论)和 Apple 的文档

在动画期间,用户交互被暂时禁用 动画中涉及的所有视图,无论 this 中的值如何 财产。您可以通过指定 配置时的 UIViewAnimationOptionAllowUserInteraction 选项 动画。

由于您的视图在屏幕上的整个过程中它都是动画块的一部分,因此在它可见的整个时间内所有交互都将被禁用。我从来没有完全测试过delay 位以及动画是否在那段期间被禁用,但我不会惊讶动画在延迟期间被禁用。第二个动画仍在主动画块内,所以我假设动画将被阻止,直到两者都完成。

【讨论】:

我可以看到视图本身...我正在设置背景颜色。我有 99.9% 的把握认为视图的框架没有问题。 为答案添加了另一种可能性。 你是绝对正确的 - 一旦我将 delay 设置为 0 并添加了 UIViewAnimationOptionAllowUserInteraction 选项,它工作正常。我现在使用 GCD 来添加延迟。对于任何感兴趣的人,我添加了更正后的 .m 文件作为答案。 使用UIViewAnimationOptionAllowUserInteraction还是无法响应tap事件,变成了event-passable,为什么?【参考方案2】:

按照@DBD 的建议更新了NotificationView.m 文件...

#import "NotificationView.h"

@implementation NotificationView

- (id)initWithMessage:(NSString*)message andColor:(UIColor*)color andKind:(NotificationKind)kind

    self = [super initWithFrame:CGRectMake(0, 0, CGRectGetWidth([UIScreen mainScreen].bounds), 60)];
    if (self) 
        // Initialization code
        [self setAlpha:0];
        [self setBackgroundColor:color];
        [self setClipsToBounds:YES];

        currentNotificationKind = kind;

        UILabel *label = [[UILabel alloc] initWithFrame:self.bounds];
        [label setNumberOfLines:0];
        [label setFont:[UIFont fontWithName:@"Roboto-Italic" size:20]];
        [label setTextColor:[UIColor whiteColor]];
        [label setTextAlignment:NSTextAlignmentCenter];
        [label setPreferredMaxLayoutWidth:290];
        [label setText:message];
        [self addSubview:label];

        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(notificationTapped)];
        [tap setNumberOfTapsRequired:1];
        [self addGestureRecognizer:tap];

        [[[UIApplication sharedApplication] keyWindow] addSubview:self];

    
    return self;


-(void)show

    [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^

        [self setAlpha:1];

     completion:nil];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC), dispatch_get_main_queue(), ^

        [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^
            [self setAlpha:0];

         completion:^(BOOL finished) 
            [self removeFromSuperview];
        ];

    );




-(void)notificationTapped

    DDLogDebug(@"Notification tapped!");



@end

【讨论】:

【参考方案3】:

假设首先调用了 makeKeyAndVisible,我最终能够通过将手势添加到应用的 keyWindow 来创建一个接受手势的全屏子视图:

myView.hidden = YES;
[[[UIApplication sharedApplication] keyWindow] addSubview:myView];

然后在状态栏上方显示:

[[UIApplication sharedApplication] keyWindow].windowLevel = UIWindowLevelStatusBar + 1;
myView.hidden = NO;

然后改回来:

[[UIApplication sharedApplication] keyWindow].windowLevel = UIWindowLevelNormal;
myView.hidden = YES;

这只是改变了应用程序主窗口(包括其所有子视图)在窗口层次结构中的位置。希望对您有所帮助!

【讨论】:

如果您找到解决方案,请告诉我 @Dutt 刚刚用我找到的解决方案编辑了我的答案。我当时应该这样做的!

以上是关于作为 UIWindow 子视图添加的 UIView 不响应点击的主要内容,如果未能解决你的问题,请参考以下文章

UIWindow 在 addSubview 之后不更新子视图

UIWindow 和 UIView addSubview 问题

我应该将底部工作表作为子视图添加到当前视图控制器还是推送添加了子视图的 UIWindow?

在 iOS 8.3 中向 UIWindow 添加子视图

即使应用程序处于后台,也可以为 UiView 设置动画

来自 UIWindow 的子视图并将其发送回 UIwindow