web-dev-qa-db-fra.com

Restaurer l'animation UINavigationController avant iOS7 pushViewController

Donc. Je viens de commencer la transition de mon code IOS vers IOS7, et j'ai rencontré un peu de problème.

J'ai un UINavigationController, qui a des ViewControllers enfants et j'utilise pushViewController pour afficher les vues suivantes. Pour créer une animation de parallaxe avec un ensemble d'images, si personnalisé le UINavigationController pour animer un ensemble de UIImageViews et mes ViewControllers enfants ont tous un self.backgroundColor = [UIColor clearColor], transparence.

Depuis iOS7, la façon dont le UINavController anime ses vc enfants, est mise à jour, en déplaçant partiellement le contrôleur de vue actuel et en poussant le nouveau viewcontroller, mon animation de parallaxe a l'air merdique. Je vois le précédent VC bouger un peu puis disparaître. Est-il possible de restaurer l'animation précédente UINavigationController pushViewController? Je n'arrive pas à trouver cela dans le code .

WelcomeLoginViewController* welcomeLoginViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"WelcomeLogin"];
    [self.navigationController pushViewController:welcomeLoginViewController animated:YES];    

Même essayé d'utiliser:

    [UIView animateWithDuration:0.75
                     animations:^{
                         [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
                         [self.navigationController pushViewController:welcomeLoginViewController animated:NO];
                         [UIView setAnimationTransition:<specific_animation_form> forView:self.navigationController.view cache:NO];
                     }];

Quelqu'un a-t-il une idée?

38
Bart van den Berg

Merci les gars pour la rétroaction. J'ai trouvé une solution pour recréer complètement le comportement de UINavigationController. Quand j'avais presque fini, je suis tombé sur la solution de Nick Lockwood:

https://github.com/nicklockwood/OSNavigationController

OSNavigationController est une réimplémentation open source de UINavigationController. Il ne comporte actuellement qu'un sous-ensemble des fonctionnalités de UINavigationController, mais l'objectif à long terme est de reproduire 100% des fonctionnalités.

OSNavigationController n'est pas vraiment destiné à être utilisé tel quel. L'idée est que vous pouvez le bifurquer puis personnaliser facilement son apparence et son comportement en fonction des exigences particulières de votre application. La personnalisation d'OSNavigationController est beaucoup plus simple que d'essayer de personnaliser UINavigationController car le code est ouvert et vous n'avez pas à vous soucier des méthodes privées, du comportement non documenté ou des changements d'implémentation entre les versions.

En remplaçant mon UINavigationController par son code, j'ai pu travailler avec des images d'arrière-plan dans UINavigationcontrollers

Merci!

2
Bart van den Berg

J'ai réussi à contourner le nouveau type de transition en créant une catégorie pour UINavigationController. Dans mon cas, je devais revenir à l'ancien style de transition car j'ai des viewControllers transparents qui glissent sur un arrière-plan statique.

  • UINavigationController + Retro.h

    @interface UINavigationController (Retro)
    
    - (void)pushViewControllerRetro:(UIViewController *)viewController;
    - (void)popViewControllerRetro;
    
    @end
    
  • UINavigationController + Retro.m

    #import "UINavigationController+Retro.h"
    
    @implementation UINavigationController (Retro)
    
    - (void)pushViewControllerRetro:(UIViewController *)viewController {
        CATransition *transition = [CATransition animation];
        transition.duration = 0.25;
        transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
        transition.type = kCATransitionPush;
        transition.subtype = kCATransitionFromRight;
        [self.view.layer addAnimation:transition forKey:nil];
    
        [self pushViewController:viewController animated:NO];
    }
    
    - (void)popViewControllerRetro {
        CATransition *transition = [CATransition animation];
        transition.duration = 0.25;
        transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
        transition.type = kCATransitionPush;
        transition.subtype = kCATransitionFromLeft;
        [self.view.layer addAnimation:transition forKey:nil];
    
        [self popViewControllerAnimated:NO];
    }
    
    @end
    
46
Arne

J'ai le même problème avec des couleurs d'arrière-plan claires et des animations merdiques, donc je crée une transition personnalisée pour ViewController avec la nouvelle API iOS7. Il vous suffit de définir un délégué pour votre contrôleur de navigation:

// NavigationController does not retain delegate, so you should hold it.
self.navigationController.delegate = self.navigationTransitioningDelegate;

Ajoutez simplement ces fichiers dans votre projet: MGNavigationTransitioningDelegate .

22
ArtFeel

J'ai eu un problème où lorsque UIViewController A a fait un pushViewController pour pousser UIViewController B, l'animation Push s'arrêtait à environ 25%, s'arrêtait, puis faisait glisser B dans le reste du chemin.

Cela DID N'EST PAS arrivé sur iOS 6, mais dès que j'ai commencé à utiliser iOS 7 comme SDK de base dans XCode 5, cela a commencé à se produire.

Le correctif est que le contrôleur de vue B n'avait pas de backgroundColor défini sur sa vue racine (la vue racine est celle qui est la valeur de viewController.view, que vous définissez généralement dans loadView). La définition d'un backgroundColor dans l'initialiseur de cette vue racine a résolu le problème.

J'ai réussi à résoudre ce problème comme suit:

// CASE 1: The root view for a UIViewController subclass that had a halting animation

- (id)initWithFrame:(CGRect)frame

{

     if ((self = [super initWithFrame:frame])) {

          // Do some initialization ...

          // self.backgroundColor was NOT being set

          // and animation in pushViewController was slow and stopped at 25% and paused

     }

     return self;

}

// CASE 2: HERE IS THE FIX

- (id)initWithFrame:(CGRect)frame

{

     if ((self = [super initWithFrame:frame])) {

          // Do some initialization ...

          // Set self.backgroundColor for the fix!

          // and animation in pushViewController is no longer slow and and no longer stopped at 25% and paused

          self.backgroundColor = [UIColor whiteColor]; // or some other non-clear color

     }

     return self;

}
18
Joel

Tout d'abord, je n'utilise pas Storyboard. J'ai essayé d'utiliser UINavigationController + Retro. Pour une raison quelconque, l'UINavigationController a du mal à libérer l'UIViewController en haut de la pile. Voici la solution qui fonctionne pour moi en utilisant la transition personnalisée iOS 7.

  1. Définissez le délégué sur lui-même.

    navigationController.delegate = self;
    
  2. Déclarez ce UINavigationControllerDelegate.

    - (id<UIViewControllerAnimatedTransitioning>)navigationController (UINavigationController *)navigationController 
    animationControllerForOperation:(UINavigationControllerOperation)operation
    fromViewController:(UIViewController *)fromVC 
    toViewController:(UIViewController *)toVC 
    {
        TransitionAnimator *animator = [TransitionAnimator new]; 
        animator.presenting = YES;
        return animator;
    }
    

    Notez qu'il ne sera appelé que lorsque animated est réglé sur YES. Par exemple

    [navigationController pushViewController:currentViewController animated:YES];
    
  3. Créez la classe d'animation étendant NSObject. J'ai appelé le mien TransitionAnimator, qui a été modifié à partir de TLTransitionAnimator de TeehanLax à l'intérieur IViewController-Transitions-Example .

    TransitionAnimator.h

    #import <Foundation/Foundation.h>
    @interface TransitionAnimator : NSObject <UIViewControllerAnimatedTransitioning>
    @property (nonatomic, assign, getter = isPresenting) BOOL presenting;
    @end
    

    TransitionAnimator.m

    #import "TransitionAnimator.h"
    @implementation TransitionAnimator
    - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext {
        return 0.5f;
    }
    - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext{
        UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
        UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];    
        if (self.presenting) {
            //ANIMATE VC ENTERING FROM THE RIGHT SIDE OF THE SCREEN
            [transitionContext.containerView addSubview:fromVC.view];
            [transitionContext.containerView addSubview:toVC.view];     
            toVC.view.frame = CGRectMake(0, 0, 2*APP_W0, APP_H0); //SET ORIGINAL POSITION toVC OFF TO THE RIGHT                
            [UIView animateWithDuration:[self transitionDuration:transitionContext] 
                animations:^{
                    fromVC.view.frame = CGRectMake(0, (-1)*APP_W0, APP_W0, APP_H0); //MOVE fromVC OFF TO THE LEFT
                    toVC.view.frame = CGRectMake(0, 0, APP_W0, APP_H0); //ANIMATE toVC IN TO OCCUPY THE SCREEN
                } completion:^(BOOL finished) {
                    [transitionContext completeTransition:YES];
                }];
        }else{
            //ANIMATE VC EXITING TO THE RIGHT SIDE OF THE SCREEN
        }
    }
    @end
    

    Utilisez le drapeau de présentation pour définir la direction que vous souhaitez animer ou la condition que vous préférez. Voici la lien à Apple référence.

7
voratima

Ajoutez simplement:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

Cette:

[[self window] setBackgroundColor:[UIColor whiteColor]];

Le résultat final:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions (NSDictionary *)launchOptions {    
    [[self window] setBackgroundColor:[UIColor whiteColor]];

    // Override point for customization after application launch.
    return YES;
}
2
Riko87

Apparemment, dans iOS7, il existe une nouvelle façon de définir vos propres transitions UIViewController personnalisées. Regardez dans les documents pour UIViewControllerTransitioningDelegate. En outre, voici un lien vers un article à ce sujet: http://www.doubleencore.com/2013/09/ios-7-custom-transitions/

1
John Jacecko

J'ai trouvé une autre excellente ressource pour vous aider:

http://www.teehanlax.com/blog/custom-uiviewcontroller-transitions

Utilisation d'iOS7 TLTransitionAnimator pour créer des animations personnalisées

0
Bart van den Berg

J'ai voté pour la réponse de @ Arne, car je trouve que c'est la solution la plus élégante à ce problème. Je voudrais juste ajouter du code afin de répondre au problème de @ Bill à partir de son commentaire sur la solution de @ Arne. Voici une citation de commentaire:

Merci, cela fonctionne pour moi. Cependant, lorsque l'utilisateur appuie sur le bouton Précédent, il revient à l'animation interrompue (car le bouton Précédent n'appelle pas popViewControllerRetro). - Bill 3 octobre à 12:36

Afin d'appeler popViewControllerRetro lorsque vous appuyez sur le bouton de retour, vous pouvez effectuer un petit piratage pour y parvenir. Allez dans votre contrôleur de vue poussé, importez UIViewController + Retro.h et ajoutez ce code dans votre méthode viewWillDisappear:

- (void)viewWillDisappear:(BOOL)animated {
    if ([self.navigationController.viewControllers indexOfObject:self] == NSNotFound) {
        [self.navigationController popViewControllerRetro];
    }

    [super viewWillDisappear:animated];
}

Cette instruction if détectera lorsque le bouton Retour est enfoncé et appellera popViewControllerRetro de la classe category.

Meilleures salutations.

0
uerceg