web-dev-qa-db-fra.com

iOS7 UIModalTransitionStyleFlipHorizontal rebondit après la transition

Je mets à jour mon application pour iOS 7 et j'ai découvert un problème étrange. Je présente un UIViewController enveloppé dans un UINavigationController avec UIModalTransitionStyleFlipHorizontal.

Dans iOS 6, cela fonctionne bien, mais dans iOS 7, la barre de navigation rebondit après la transition. Cela a-t-il quelque chose à voir avec la barre d'état? J'ai défini la translucidité de la barre de navigation principale sur NO.

Dans Info.plist, Afficher l'apparence de la barre d'état basée sur le contrôleur est défini sur NON.

Et voici un GIF montrant le problème dans une application de démonstration minimale:

enter image description here

Voici mon 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];
73
Rene

Cela semble être un bug UIKit. La solution de contournement suivante semble résoudre le problème pour moi.

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

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

(Placez-le dans le contrôleur de vue que vous transformez vers).

54
Ben Packard

Pour résoudre ce problème pour le présent et le rejeter, j'utilise la transition personnalisée iOS7.

Ajoutez ceci à votre 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];
                    }];
}

Pour l'utiliser, il vous suffit de vérifier si vous êtes sur iOS7 et de définir la 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];

Dans mon cas, j'avais un UINavigationController personnalisé où la transition personnalisée est définie: je n'ai pas à le faire à chaque fois.

16
EricD

Cela semble être un bug UIKit. La solution de contournement suivante semble résoudre le problème pour moi.

presentViewController (placez-le dans le contrôleur de vue vers lequel vous effectuez la transition):

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

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

dismissViewControllerAnimated (placez-le dans le contrôleur de vue auquel vous rejetez):

- (void)viewWillLayoutSubviews{
    [super viewWillLayoutSubviews];

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

si vous n'utilisez pas autolayout. vous devez l'ajouter au contrôleur de vue auquel vous dismiss:

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

    [self.view setNeedsLayout];
} 
9
dusty

J'ai eu le même problème et j'ai pu le "résoudre" (ce n'est pas une vraie solution au problème mais ça a l'air bien :)). L'astuce est de présenter le contrôleur de vue en utilisant pushViewController/popViewController avec une animation UIView pour faire un flip. Voici un exemple de code pour présenter le contrôleur de vue:

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

Pour le rejeter:

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

Si vous ne voulez pas que le navigationBar sur le contrôleur poussé appelez simplement [self.navigationController setNavigationBarHidden:YES animated:NO] dans viewWillAppear. J'espère que cette approche vous aidera.

3
RemeR

Pour le contrôleur de présentation et la vue présentée, j'ai un UITableViewController dans UINavigationController, tous deux configurés à l'aide de la disposition automatique. J'ai remarqué que les autres réponses n'ont pas résolu le problème qui, lors du rejet de la tableView du contrôleur de vue présent, saute de 20 pt verticalement.

Cette solution résout ce problème.

Dans le contrôleur de vue présenté (comme proposé par Ben Packard):

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

Dans le contrôleur de vue présenté (comme proposé en partie par poussiéreux):

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