2013-10-14

FIX: A blank view appears after QLPreviewController dismissed in iOS 7

Recently when I am working with iOS 7, I encounter the following problem: If the modalPresentationStyle of an view controller is set as UIModalPresentationFormSheet or UIModalPresentationPageSheet and after one uses the QLPreviewController once in the view controller and dismisses the Quick Look, a blank / gray view will appear on the screen instead of the presented view controller. This blank view cannot be dismissed or interacted.

That seems a serious bug in iOS 7. :(

After some days trying errors, I've found the following workaround:

in the presenting ViewController:

if ([self DeviceSystemMajorVersion] >= 7) {
modalVC.transitioningDelegate = self;
modalVC.modalPresentationStyle = UIModalPresentationCustom;
} else {
modalVC.modalPresentationStyle = UIModalPresentationFormSheet;
}


The function to detect iOS 7:

- (NSUInteger) DeviceSystemMajorVersion {
    static NSUInteger _deviceSystemMajorVersion = -1;
    static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_deviceSystemMajorVersion = [[[[[UIDevice currentDevice] systemVersion] componentsSeparatedByString:@"."] objectAtIndex:0] intValue];
});
return _deviceSystemMajorVersion;
}


The presenting view controller should conform to the protocol UIViewControllerAnimatedTransitioning and UIViewControllerTransitioningDelegate, in order to use the custom transaction style that indroduced in iOS 7. Continue to add these methods:

- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented
                                                                  presentingController:(UIViewController *)presenting
                                                                      sourceController:(UIViewController *)source {
return self;
}
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
UIView *inView = [transitionContext containerView];
    UIView *toView = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey].view;
    UIView *fromView = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey].view;
UIView *preferenceOverlay = [[UIView alloc] initWithFrame:inView.frame];
preferenceOverlay.backgroundColor = [UIColor blackColor];
preferenceOverlay.alpha = 0;
[inView addSubview:preferenceOverlay];
toView.frame = CGRectMake(0, 0, 540, 540);
toView.center = CGPointMake(CGRectGetMidX(inView.frame), CGRectGetMidY(inView.frame));
[inView addSubview:toView];
    [UIView animateKeyframesWithDuration:(1.0) delay:0 options:0 animations:^{
preferenceOverlay.alpha = 0.4;
    } completion:^(BOOL finished) {
        [transitionContext completeTransition:finished];
    }];
}


Then in the presented view controller:

-(void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
if ([self DeviceSystemMajorVersion] >= 7) {
if (QLOpened) {
self.view.frame = CGRectMake(0, 0, 540, 540);
CGFloat xCenter = CGRectGetMidX(self.view.superview.frame) + 125;
CGFloat yCenter = CGRectGetMidY(self.view.superview.frame) - 125;
self.view.center = CGPointMake(xCenter, yCenter);
NSLog(@"Center X:%f Y:%f",xCenter,yCenter);
}
}
}


Then let the view controller to conform the protocol QLPreviewControllerDelegate and add the following method:
- (void)previewControllerWillDismiss:(QLPreviewController *)controller {
NSLog(@"QLView dismissed");
[self.view setNeedsLayout];
}


DONE!

If you have the centering problem of the modal view controller, try fine-tuning the center point of the method viewWillLayoutSubviews

No comments: