Question

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

Was it helpful?

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).

OTHER TIPS

Found new solution.

In info.plist file add this for iOS 7: UIViewControllerBasedStatusBarAppearance (View controller-based status bar appearance) = NO

These solutions didn't work for me. The only solution I found was to force status bar visible on the next runloop after delegate requesting the presenting view controller (need UIViewControllerBasedStatusBarAppearance set to NO also):

- (UIViewController *) documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *) controller {
    // hack to keep status bar visible
    [[NSOperationQueue mainQueue] addOperationWithBlock:
     ^{
         [[UIApplication sharedApplication] setStatusBarHidden:NO];
     }];
    return self.viewController;
}

Try Below Code it works for me :

- (void)documentInteractionControllerWillBeginPreview:(UIDocumentInteractionController *)controller
{
    [[UIApplication sharedApplication] setStatusBarHidden:YES];
}

- (void)documentInteractionControllerDidEndPreview:(UIDocumentInteractionController *)controller
{
    [[UIApplication sharedApplication] setStatusBarHidden:YES];
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top