在iOS 7 iPad上,有时候关闭UIDocumentInteractionController会导致呈现视图控制器的视图被移除。

10
当 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; }
- Chamira Fernando
同样的问题在这里...在委托中,我的方法返回self.view。 - matti157
3个回答

4

当我在iOS 7的iPad上以模态表单表格形式呈现视图控制器时,从UIDocumentInteractionController中呈现视图时出现了相同的问题(在iOS 6中正常工作)。

看起来,在从文档交互控制器返回到呈现视图控制器的过程中,呈现视图控制器的视图被包装在临时的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;
        }
    }
}

迈克尔 - 你用什么工具来检查视图层次结构? - Chris Markle
在调试器中,输入 po [yourView recursiveDescription] 以获取视图层次结构。 - elp

2
我发现Michael Kuntscher的回答非常准确。如果UIDocumentInteractionController是从弹出窗口中呈现的,则需要进行轻微修改。
在视图层次结构上稍微有些依赖性,可以通过迭代父视图来消除,直到找到一个具有UIWindow父视图的视图为止。此外,我发现当文档交互控制器从弹出窗口中呈现时,需要存储略有不同的视图作为parentView和containerView(具体而言,我们要找到一个containerView,使其父视图是UIPopoverView)。以下代码片段是对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 */
}

0

我也遇到了同样的问题,应用程序在一个灰色的表单表视图上停滞不前,这个表视图在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中,导航控制器视图的父视图现在是一个UITransistionView。但是很快(当转换完成时),它被设置为nil。不知何故,它已经与UIDropShadowView分离(或未重新附加)。通过在呈现UIDocumentInteractionController时保留对此视图的引用,我们可以手动重新附加它,并且一切正常。然后确保将引用设置为nil,以确保我们不会意外地保留它。

此方法不影响iOS 6或任何早期版本的行为。


我的情况下documentInteractionControllerDidEndPreview没有被调用。有什么帮助吗? - Mayank Jain
@MayankJain,你在创建UIDocumentInteractionController时设置了代理吗?当方法被调用时,你作为代理的对象是否仍然存在(即没有因为离开屏幕等原因而被删除)? - Rob B

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接