【问题标题】:Dismissing a UIDocumentInteractionController in some cases will remove the presenting view controller's views in IOS 7 iPad在某些情况下关闭 UIDocumentInteractionController 将删除 IOS 7 iPad 中呈现视图控制器的视图
【发布时间】:2013-10-19 05:26:30
【问题描述】:

当 UIDocumentInteractionController 被解除时,呈现视图控制器的视图将被删除,包括 UINavigationController 中的元素。

UIDocumentInteractionController 关闭,呈现视图控制器的视图被移除,在呈现视图控制器以前存在的地方留下一个纯白色/灰色框。此后,应用不再响应任何触摸事件。

这发生在运行 iOS 7 的 iPad 模拟器 (iOS 7.0) 和 iPad 3 (Wifi) 上,用于快速查看 PDF 阅读器。

不管应用程序是针对 iOS 6.1 还是 iOS 7 SDK 编译的

请告诉我你的建议。

【问题讨论】:

  • 您的委托方法如下所示 - (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *)controller { return self.navigationController; }
  • 同样的问题...在委托我的方法返回 self.view

标签: iphone objective-c ipad ios7 ipad-3


【解决方案1】:

在 iOS 7(在 iOS 6 中运行良好)从视图控制器呈现 UIDocumentInteractionController 时,我遇到了同样的问题。

看起来在从文档交互控制器转换回呈现视图控制器的过程中,呈现视图控制器的视图被包装在一个临时 UITransitionView 中,然后在转换后该转换视图被从视图层次结构中删除完成,连同呈现视图控制器的视图,只留下 UIDropShadowView,它是可见的模态表单的支持视图(灰色框)。

当文档交互控制器预览开始时,我通过保留对呈现视图控制器的根视图(层次结构中投影视图之前的那个)的引用来解决该问题,并在开始时将该视图恢复到层次结构中文档交互控制器预览已结束。

这里是示例代码:

    - (void)documentInteractionControllerWillBeginPreview:(__unused UIDocumentInteractionController *)controller {

    if (UIUserInterfaceIdiomPad == UI_USER_INTERFACE_IDIOM()) {
        // work around iOS 7 bug on ipad

        self.parentView = [[[self.view superview] superview] superview];
        self.containerView = [self.parentView superview];

        if (![[self.containerView superview] isKindOfClass: [UIWindow class]]) {
            // our assumption about the view hierarchy is broken, abort
            self.containerView = nil;
            self.parentView = nil;
        }
    }
}

    - (void)documentInteractionControllerDidEndPreview:(__unused UIDocumentInteractionController *)controller {

    if (UIUserInterfaceIdiomPad == UI_USER_INTERFACE_IDIOM()) {
        if (!self.view.window && self.containerView) {
            assert(self.parentView);
            CGRect frame = self.parentView.frame;
            frame.origin = CGPointZero;
            self.parentView.frame = frame;
            [self.containerView addSubview: self.parentView];
            self.containerView = nil;
            self.parentView = nil;
        }
    }
}

【讨论】:

  • Michael - 您使用什么工具来检查视图层次结构?
  • @ChrisMarkle 在调试器中,写入po [yourView recursiveDescription] 以获取层次结构。
【解决方案2】:

我发现 Michael Kuntscher 的答案是正确的。如果 UIDocumentInteractionController 是从弹出窗口中呈现的,则需要稍作修改。

通过遍历父视图直到找到具有 UIWindow 父视图的视图,可以消除对视图层次结构的轻微依赖。此外,我发现当一个文档交互控制器从一个弹出窗口中呈现时,需要将其存储为 parentView 和 containerView 的视图略有不同(具体来说,我们希望找到一个 containerView,使其超级视图是 UIPopoverView)。以下 sn-p 是 Michael 的答案的重新设计版本,用于合并这些更改(请注意 UIPopoverView 是一个私有类,因此我们使用该类的字符串表示,而不是直接引用每个类):

- (void)documentInteractionControllerWillBeginPreview:(UIDocumentInteractionController *)controller {

    /* iOS 7 DIC bug workaround  */
    if (UIUserInterfaceIdiomPad == UI_USER_INTERFACE_IDIOM()) {
        UIView *a_view = self.view;

        self.dicParentView = nil;
        self.dicContainerView = nil;

        while (a_view != nil) {
            UIView *super_super_view = [[a_view superview] superview];
            NSString *str_class = NSStringFromClass([super_super_view class]);

            if ([str_class isEqualToString:@"UIWindow"] ||
                [str_class hasSuffix:@"PopoverView"]) {
                self.dicParentView = a_view;
                self.dicContainerView = [a_view superview];
                break;
            }
            a_view = [a_view superview];
        }

        if (self.dicParentView == nil) {
            NSLog(@"Could not appropriate superview, unable to workaround DIC bug");
        }
    }
    /* end work around */
}

- (void)documentInteractionControllerDidEndPreview:(__unused UIDocumentInteractionController *)controller {
    /* iOS 7 DIC bug workaround */
    if (UIUserInterfaceIdiomPad == UI_USER_INTERFACE_IDIOM()) {
        if ((self.view.window == nil) &&
            (self.dicContainerView != nil) &&
            (self.dicParentView != nil)) {
            NSLog(@"Restoring view for DIC presenter in the view hierarchy");
            CGRect frame = self.dicParentView.frame;
            frame.origin = CGPointZero;
            self.dicParentView.frame = frame;
            [self.dicContainerView addSubview: self.dicParentView];
            self.dicContainerView = nil;
            self.dicParentView = nil;
        }
    }
    /* end work around */
}

【讨论】:

    【解决方案3】:

    在呈现和关闭 UIDocumentInteractionController 后,应用程序在灰色表单模式视图上停止运行时遇到了完全相同的问题,该模式视图丢失了所有内容。这里的两个解决方案很棒,但我简化了它们以适应我的特殊情况,它是表单模式中的 UINavigationController,可以在 UIDocumentInteractionController 中呈现 PDF,我希望它是全屏模式而不是在导航控制器中推送因为表单区域太小,PDF 难以阅读。

    我实现了两个 UIDocumentInteractionControllerDelegate 方法。假设如下:

    • self.navController 是对 UINavigationController 的引用,它显示在表单模式中。
    • 在UIViewController子类@property (nonatomic, strong) UIView* docInteractionControllerWorkaroundSuperview;中声明了一个成员变量
    • SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO 是 #define([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)

    首先:

    -(UIViewController*)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController*)controller
    {    
        if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0") && self.navigationController.modalPresentationStyle == UIModalPresentationFormSheet)
        {
            self.docInteractionControllerWorkaroundSuperview = [self.navigationController.view superview];
        }
        return self.navigationController.visibleViewController;
    }
    

    然后:

    - (void)documentInteractionControllerDidEndPreview:(UIDocumentInteractionController *)controller
    {
        if (self.docInteractionControllerWorkaroundSuperview != nil)
        {
            NSLog(@"Workaround iOS 7 document interaction bug... resetting nav controller view into modal");
    
            //reset the nav controller view from whence it came.
            self.navigationController.view.frame = CGRectMake(0.0, 0.0, self.navigationController.view.frame.size.width, self.navigationController.view.frame.size.height);
            [self.docInteractionControllerWorkaroundSuperview addSubview:self.navigationController.view];
    
            self.docInteractionControllerWorkaroundSuperview = nil;
        }
    }
    

    即呈现 UIDocumentInteractionController 时,请查看导航控制器视图的超级视图。它是一个 UIDropShadowView,我假设它是表单模式的部分透明灰色/黑色背景,它使呈现模式的背后的视图变暗。

    当 PDF 被关闭时,在documentInteractionControllerDidEndPreview 中,导航控制器视图的超级视图现在是 UITransitionView。但是在那之后不久(当转换完成时),它被设置为 nil。不知何故,它与 UIDropShadowView 分离(或没有重新连接)。通过在呈现 UIDocumentInteractionController 时保留对视图的引用,我们可以手动重新附加它,一切正常。然后一定要取消引用,以确保我们不会意外保留它。

    此方法不会影响 iOS 6 或任何以前的 iOS 版本上的行为。

    【讨论】:

    • documentInteractionControllerDidEndPreview 在我的情况下没有被调用。有什么帮助吗?
    • @MayankJain 您在创建 UIDocumentInteractionController 时是否设置了委托?当方法被调用时,您创建委托的对象是否仍然存在(即尚未因离开屏幕等而被删除)?
    猜你喜欢
    • 2020-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-06
    • 1970-01-01
    相关资源
    最近更新 更多