Carl Sjogreen Carl Sjogreen - 6 months ago 52
Objective-C Question

How do I update the StatusBar Style as part of a custom transition

I'm using the iOS 7

UIviewControllerAnimatedTransitioning
protocol to present a modal
ViewController
with a custom animation. The animation works correctly, however, I want the newly presented
ViewController
to have a different status bar style than the presenting VC.

What I'm seeing is that
-(UIStatusBarStyle)preferredStatusBarStyle
gets called on the PRESENTING
ViewController
(several times in fact) and never on the newly presented
ViewController
. If I remove the custom animation everything with the status bar works as I'd expect.

Is there something special I need to do in my animateTransition function to update the root view controller or something? I've tried manually setting the statusBar with
[UIApplication sharedApplication] setStatusBarStyle
but it doesn't work (I think because I'm using the ios 7 view controller based status bar styling).

This is my code for animateTransition:

- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UICollectionViewCell *activeCell;
if ([self.collectionView.visibleCells containsObject:self.cellForActiveIdeaVC]) {
activeCell = self.cellForActiveIdeaVC;
}

UIView *container = transitionContext.containerView;
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView *fromView = fromVC.view;
UIView *toView = toVC.view;

CGRect beginFrame;
if (activeCell) {
beginFrame = [container convertRect:activeCell.bounds fromView:activeCell];
} else {
beginFrame = CGRectMake(container.width / 2, container.height / 2, 0, 0);
}

CGRect endFrame = [transitionContext initialFrameForViewController:fromVC];

UIView *move = nil;
if (toVC.isBeingPresented) {
toView.frame = endFrame;
move = [toView snapshotViewAfterScreenUpdates:YES];
move.frame = beginFrame;
} else {
if (activeCell) {
move = [activeCell snapshotViewAfterScreenUpdates:YES];
} else {
move = [fromView snapshotViewAfterScreenUpdates:YES];
}
move.frame = fromView.frame;
[fromView removeFromSuperview];
}
[container addSubview:move];

[UIView animateWithDuration:.5
delay:0
usingSpringWithDamping:700
initialSpringVelocity:15
options:0
animations:^{
move.frame = toVC.isBeingPresented ? endFrame : beginFrame;
}
completion:^(BOOL finished) {
[move removeFromSuperview];

if (toVC.isBeingPresented) {
toView.frame = endFrame;
[container addSubview:toView];
} else {
if (self.cellForActiveIdeaVC) {
self.cellForActiveIdeaVC = nil;
}
}

[transitionContext completeTransition:YES];
}];
}


Any pointers much appreciated!

Answer

With iOS 7 custom transitions, it's possible to present a view controller that isn't fullscreen and therefore wouldn't affect the statusbar appearance. You have to explicitly tell iOS that your custom presented view controller will, in fact, control the status bar's appearance.

UIViewController *controllerToPresent = [...]
controllerToPresent.modalPresentationStyle = UIModalPresentationStyleCustom;
controllerToPresent.modalPresentationCapturesStatusBarAppearance = YES;

[self presentViewController:controllerToPresent animated:YES completion:nil];

There's some more information here. Hope that helps!