iOS7 UIModalTransitionStyleFlipHorizontal bounces after transition

IosCocoa TouchUiviewcontrollerUinavigationcontrollerUimodaltransitionstyle

Ios Problem Overview


I'm updating my app for iOS 7 and I discovered a weird problem. I'm presenting a UIViewController wrapped in a UINavigationController with UIModalTransitionStyleFlipHorizontal.

In iOS 6 it works fine, but in iOS 7 the navigation bar bounces after the transition. Does this have something to do with the status bar? I've set translucency of the main navigation bar to NO.

In the Info.plist, View controller-based status bar appearance is set to NO.

And here is a GIF showing the problem in a minimal demo app:

enter image description here

Here is my code:

feedNavigationController = [[UINavigationController alloc] init];
feedNavigationController.navigationBar.translucent = NO;

SettingsViewController *settingsVC = [[SettingsViewController alloc] init];

feedNavigationController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[feedNavigationController setViewControllers:[NSArray arrayWithObjects:settingsVC, nil]];

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

Ios Solutions


Solution 1 - Ios

This appears to be a UIKit bug. The following workaround seems to resolve the issue for me.

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

    [self.navigationController.navigationBar.layer removeAllAnimations];
}

(Place this in the view controller you are transitioning to).

Solution 2 - Ios

To solve this problem for present & dismiss, I use the iOS7 custom transition.

Add this to your UIViewController :

- (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
    return (id<UIViewControllerAnimatedTransitioning>)self;
}

- (id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
    return (id<UIViewControllerAnimatedTransitioning>)self;
}

- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext {
    return 0.7f;
}

- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
    UIView *containerView = [transitionContext containerView];
    
    
    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    [containerView addSubview:fromVC.view];
    
    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    [containerView addSubview:toVC.view];
    
    UIViewAnimationOptions animationOption = ([toVC.presentedViewController isEqual:fromVC])?UIViewAnimationOptionTransitionFlipFromLeft:UIViewAnimationOptionTransitionFlipFromRight;
    

    [UIView transitionFromView:fromVC.view
                        toView:toVC.view
                      duration:[self transitionDuration:transitionContext]
                       options:animationOption
                    completion:^(BOOL finished) {
                        [transitionContext completeTransition:YES];
                    }];
}

To use it, you just had to check if you are on iOS7 and set the transitionDelegate :

YourVCWithTheCustomTransition* yourVC = [[YourVCWithTheCustomTransition alloc] init];

CGFloat deviceVersion = [UIDevice currentDevice].systemVersion.floatValue;
if(deviceVersion >= 7.0) [yourVC setTransitioningDelegate:yourVC];

[self presentModalViewController:yourVC animated:YES];
[yourVC release];

In my case, I had a custom UINavigationController where the custom transition is defined : i don't have to do this each time.

Solution 3 - Ios

This appears to be a UIKit bug. The following workaround seems to resolve the issue for me.

presentViewController (place this in the view controller you are transitioning to):

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

    [self.navigationController.navigationBar.layer removeAllAnimations];
}

dismissViewControllerAnimated (place this in the view controller you dismiss to):

- (void)viewWillLayoutSubviews{
    [super viewWillLayoutSubviews];
    
    [self.navigationController.navigationBar.layer removeAllAnimations];
}

if you don't use autolayout. you need add this to the view controller you dismiss to:

- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    
    [self.view setNeedsLayout];
} 

Solution 4 - Ios

I had the same issue and could "solve it" (it's not a real solution to the problem but it looks fine :) ). The trick is present the view controller using pushViewController/popViewController with an UIView animation to make a flip. Here is a example code to present the view controller:

UIViewController *viewController = [[UIViewController alloc] init];
[UIView transitionWithView:self.navigationController.view 
                  duration:0.5 
                   options:UIViewAnimationOptionTransitionFlipFromLeft 
                animations:^{
                   [self.navigationController pushViewController:viewController animated:NO];
                }
                completion:nil];

To dismiss it:

[UIView transitionWithView:self.navigationController.view 
                  duration:0.5 
                   options:UIViewAnimationOptionTransitionFlipFromRight 
                animations:^{
                   [self.navigationController popViewControllerAnimated:NO];
                }
                completion:nil];

If you don't want the navigationBar on the pushed controller just call [self.navigationController setNavigationBarHidden:YES animated:NO] in viewWillAppear. I hope this approach help you.

Solution 5 - Ios

For both the presenting and the presented view controller I have a UITableViewController within UINavigationController, both configured using Auto Layout. I noticed that the other answers didn't solve the problem that on dismiss the tableView of the presenting view controller jumps 20 pt vertically.

This solution addresses this problem.

In the presented view controller (as proposed by Ben Packard):

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self.navigationController.navigationBar.layer removeAllAnimations];
}

In the presenting view controller (as proposed in part by dusty):

- (void)viewWillLayoutSubviews{
	if (self.navigationController.presentedViewController) {
		[self.navigationController.navigationBar.layer removeAllAnimations];
		[self.tableView.layer removeAllAnimations];
	}
    [super viewWillLayoutSubviews];
}

Solution 6 - Ios

The same for me. What actually worked is to change style to CoverVertical, looks much smoother.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionReneView Question on Stackoverflow
Solution 1 - IosBen PackardView Answer on Stackoverflow
Solution 2 - IosEricDView Answer on Stackoverflow
Solution 3 - IosHugoView Answer on Stackoverflow
Solution 4 - IosRemeRView Answer on Stackoverflow
Solution 5 - IosOrtwin GentzView Answer on Stackoverflow
Solution 6 - IostiticacaView Answer on Stackoverflow