Search code examples
ioscocoa-touchios7statusbaruidocumentinteraction

Document interaction controller with iOS 7 status bar?


The UIDocumentInteractionController seems to have trouble interacting properly with the new iOS 7 status bar particularly in landscape orientation. The code I have for displaying the viewer right now:

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"example" ofType:@"pdf"];
    NSURL *url = [NSURL fileURLWithPath:filePath];

    UIDocumentInteractionController *pdfViewer = [UIDocumentInteractionController interactionControllerWithURL:url];
    [pdfViewer setDelegate:self];
    [pdfViewer presentPreviewAnimated:YES];
}

- (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *)controller
{
    return self;
}

- (UIView *)documentInteractionControllerViewForPreview:(UIDocumentInteractionController *)controller
{
    return self.view;
}

When the interaction controller first appears the status bar overlaps the title.

enter image description here

Rotating to landscape on the other side fixes the behaviour temporarily.

enter image description here

As expected tapping on the document itself allows dismisses the frame. However once the document is tapped once more to activate the frame the overlap occurs again as with the first image.

I have tried setting documentInteractionControllerRectForPreview to no avail.

- (CGRect)documentInteractionControllerRectForPreview:(UIDocumentInteractionController *)controller
{
    return CGRectMake(0, 20, self.view.bounds.size.width, self.view.bounds.size.height);
}

I do not wish to hide the status bar when the interaction controller comes up and I assume it is possible to do this correctly since the Mail app behaves correctly and it looks like it is using the same class.

A minimal example project attached for anyone who wants to play with the code: https://hostr.co/PiluL1VSToVt


Solution

  • I solved this by wrapping the UIDocumentInteractionController in a UINavigationController and switching the application window's root view controller to the navigation controller for presentation. In my usage the other view controllers were not using UINavigationController so upon dismissal we swap the old root controller back:

    #import "MainViewController.h"
    
    @interface MainViewController ()
    
    @property (nonatomic, strong) UINavigationController *navController;
    @property (nonatomic, strong) MainViewController *main;
    
    @end
    
    @implementation MainViewController
    
    - (void)viewDidAppear:(BOOL)animated
    {
        [super viewDidAppear:animated];
    
        self.main = self;
        self.navController = [[UINavigationController alloc] initWithRootViewController:[UIViewController new]];
        [[UIApplication sharedApplication].keyWindow setRootViewController:self.navController];
    
        NSString *filePath = [[NSBundle mainBundle] pathForResource:@"example" ofType:@"pdf"];
        NSURL *url = [NSURL fileURLWithPath:filePath];
    
        UIDocumentInteractionController *pdfViewer = [UIDocumentInteractionController interactionControllerWithURL:url];
        [pdfViewer setDelegate:self];
        [pdfViewer presentPreviewAnimated:YES];
    }
    
    - (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *)controller
    {
        return self.navController;
    }
    
    - (void)documentInteractionControllerDidEndPreview:(UIDocumentInteractionController *)controller
    {
        [[UIApplication sharedApplication].keyWindow setRootViewController:self.main];
        self.main = nil;
    }
    
    - (void)dismiss
    {
        [self.navController popViewControllerAnimated:YES];
    }
    
    @end
    

    The dummy view controller allows the interaction controller to be popped (back button).