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:
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];
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).
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.
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];
}
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.
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];
}