ios - 用覆盖层覆盖 UIAppDelegate 的窗口使用户在显示时无法触摸 UIActivityViewController 的扩展

标签 ios objective-c swift

我正在创建一个叠加层,它将覆盖屏幕上所有显示的 View 。即使 rootViewController 发生变化、推送或呈现,此叠加层也会始终出现。

我的想法是

  • 创建 CustomWindow,它是 UIWindow 的子类。将 UIApplication 的默认 window 替换为 CustomWindow 之后,为我的新窗口创建一个新的 rootViewController
  • CustomWindow 中,我有一个 overlay(是一个 UIView)。 Overlay 具有带 alpha 的浅灰色,overlay 上的每个事件都将传递到下面的 View 。
  • 每当 CustomWindow 添加一个新的 subview 时,我都会将 overlay 放在前面。它确保 overlay 在任何情况下都位于顶部。

自定义窗口

@implementation CustomWindow

- (instancetype)initWithFrame:(CGRect)frame {
  self = [super initWithFrame:frame];

  if (self) {
    _overlay = [[UIView alloc] initWithFrame:self.bounds];
    _overlay.userInteractionEnabled = NO;
    _overlay.backgroundColor = [UIColor lightGrayColor];
    _overlay.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    [self addSubview:_overlay];
  }

  return self;
}

- (void)didAddSubview:(UIView *)subview {
  [super didAddSubview:subview];

  [self bringSubviewToFront:_overlay];
}

@end

即使在推送、呈现或更改 rootViewController 时,在任何情况下都一切正常。

问题

但是当我显示 UIActivityViewController 时,我无法点击显示在 UIActivityViewController 上的任何扩展。

神奇地

  • 当我在 UIActivityViewController 之外单击或单击 Cancel Button 时,UIActivityViewController 会正常关闭。

    <
  • 如果我将 overlay 的颜色更改为 clearColor,它也能正常工作。

我的问题是

  • 当我在窗口上有 overlay 并且 overlay 有颜色时,如何触摸扩展?

  • 如果我不能,谁能告诉我为什么会这样?当您可以从文档中引用原因时,这是完美的。

我很确定这与我如何初始化 UIActivityViewController 或我显示 UIActivityViewController 的方式无关。

更多

我找到了一个 problemAndroid 上的这个问题非常相似。但我不确定,因为我还没有看到 Apple 的任何官方文件。还有一件事是,将颜色更改为 clearColor 会影响触摸。所以实际上,我认为它们并不相同。

最佳答案

这是由于层次结构中的 UIRemoveView(私有(private))所致。据我所知,您的应用无法将事件直接转发到远程 View 。我怀疑这是一种安全措施,可防止您显示共享对话框并自动向其发送触摸事件以执行用户未请求的外部操作。远程 View 不在您的应用程序进程中运行。 “复制”按钮通过 XPC 链接进行交互。

这一切都意味着,如果远程 View 被您的其中一个 View 覆盖,则无法(至少我已经找到)与之交互。你必须确保你没有覆盖它。

其实这样做很简单。保存远程 View 的东西称为 UITransitionView 并且用于您可能也不应该涵盖的其他操作系统级别的东西。所以不要:

- (void)didAddSubview:(UIView *)subview {
    [super didAddSubview:subview];

    if ([subview isKindOfClass:NSClassFromString(@"UITransitionView")]) {
        // To raise it above your overlay;
        // otherwise it's immediately above the view controller (below the overlay)
        [self bringSubviewToFront:subview];
    } else {
        [self bringSubviewToFront:self.overlay];
    }
}

但是....这需要你在代码中谈论UITransitionView。这既脆弱,也可能禁止使用私有(private) API。

否则你必须用一些调用/通知来包装你的 UIActivityViewController 请求,告诉窗口在我们完成之前不要覆盖 View (你必须在完成处理程序中清除)。

关于ios - 用覆盖层覆盖 UIAppDelegate 的窗口使用户在显示时无法触摸 UIActivityViewController 的扩展,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47109982/

相关文章:

swift - Rx swift : Extra argument 'onError' when subscribing on an Observable<String>

ios - Xcode 10、11 - 无法发出预编译 header

iOS View Controller 生命周期

ios - 在 NSMutableArray Parse iOS 中删除 currentUser

ios - UIButton 按下时改变状态

ios - AudioServicesCreateSystemSoundID 不播放 mp3 文件

ios - Swift 扩展 UIView 返回调用类型

ios - UICollectionView 委托(delegate)未被调用

ios - 循环坐标并找到距离 Swift 3 点最近的商店

swift - Github exyte Macaw-示例快速编译器错误