Restaurar a animação pushViewController do pré-iOS7 UINavigationController

Assim. Comecei a fazer a transição do meu código IOS para o IOS7 e tive um pequeno problema.

Eu tenho um UINavigationController , que tem filhos ViewControllers e estou usando o pushViewController para exibir as próximas exibições. Para criar uma animação de paralaxe com um conjunto de imagens, se personalizado, o UINavigationController para animar um conjunto de UIImageViews e meus filhos ViewControllers terão um self.backgroundColor = [UIColor clearColor] , transparência.

Desde o iOS7, a forma como o UINavController anima, vc’s, é atualizada, movendo parcialmente o controlador de visualização atual e, no topo, empurrando o novo viewcontroller, minha animação de paralaxe parece uma porcaria. Eu vejo o VC anterior se mover um pouco e depois desaparecer. Existe alguma maneira de restaurar a animação pushViewController anterior do UINavigationController ? Eu não consigo encontrar isso no código.

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

Até tentei usar:

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

Alguem tem alguma ideia?

Eu consegui contornar o novo tipo de transição criando uma categoria para o UINavigationController . No meu caso, precisei revertê-lo para o estilo de transição antigo, porque tenho viewControllers transparentes que deslizam sobre um plano de fundo estático.

  • 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 

Eu tenho o mesmo problema com colors claras de fundo e animações ruins, então eu crio a transição personalizada para o ViewController com a nova API do iOS7. Tudo que você precisa é simplesmente definir um delegado para o seu controlador de navegação:

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

Basta adicionar esses arquivos ao seu projeto: MGNavigationTransitioningDelegate .

Eu tive um problema onde quando UIViewController A fez um pushViewController para empurrar UIViewController B, a animação de push pararia em cerca de 25%, parada e, em seguida, deslize B no resto do caminho.

Isso NÃO aconteceu no iOS 6, mas assim que comecei a usar o iOS 7 como o SDK de base no XCode 5, isso começou a acontecer.

A correção é que o controlador de visualização B não tinha um backgroundColor definido em sua visualização raiz (a visualização raiz é aquela que é o valor de viewController.view, que você normalmente configura em loadView). Definir um backgroundColor no inicializador dessa visão raiz corrigiu o problema.

Eu consegui consertar isso da seguinte forma:

 // 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; } 

Primeiro, não estou usando o Storyboard. Eu tentei usar o UINavigationController + Retro. Por algum motivo, o UINavigationController está tendo dificuldade em liberar o UIViewController no topo da pilha. Aqui está a solução que funciona para mim usando a transição personalizada do iOS 7.

  1. Definir delegado para si mesmo.

     navigationController.delegate = self; 
  2. Declare este UINavigationControllerDelegate.

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

    Note que ele só será chamado quando animado estiver definido como YES. Por exemplo

     [navigationController pushViewController:currentViewController animated:YES]; 
  3. Crie a class de animação estendendo NSObject. Eu chamei o meu TransitionAnimator, que foi modificado do TLTransitionAnimator da TeehanLax dentro do UIViewController-Transitions-Example .

    TransitionAnimator.h

     #import  @interface TransitionAnimator : NSObject  @property (nonatomic, assign, getter = isPresenting) BOOL presenting; @end 

    TransitionAnimator.m

     #import "TransitionAnimator.h" @implementation TransitionAnimator - (NSTimeInterval)transitionDuration:(id )transitionContext { return 0.5f; } - (void)animateTransition:(id )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 

    Use o sinalizador de apresentação para definir a direção que você deseja animar ou qual condição você preferir. Aqui está o link para a referência da Apple.

Obrigado pessoal pelo feedback. Encontrou uma solução para recriar completamente o comportamento do UINavigationController. Quando estava quase terminando, encontrei a solução de Nick Lockwood:

https://github.com/nicklockwood/OSNavigationController

O OSNavigationController é uma reimplementação de código-fonte aberto do UINavigationController. Atualmente, ele apresenta apenas um subconjunto da funcionalidade do UINavigationController, mas o objective de longo prazo é replicar 100% dos resources.

OSNavigationController não é realmente destinado a ser usado como está. A ideia é que você possa separá-lo e personalizar facilmente sua aparência e comportamento para atender a quaisquer requisitos especiais que seu aplicativo possa ter. Customizar o OSNavigationController é muito mais simples do que tentar customizar o UINavigationController devido ao fato de que o código está aberto e você não precisa se preocupar com methods privados, comportamento não documentado ou mudanças de implementação entre versões.

Substituindo meu UINavigationController por seu código, eu consegui trabalhar com imagens de plano de fundo em UINavigationcontrollers

Obrigado!

Basta adicionar:

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

Este:

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

O resultado final:

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions (NSDictionary *)launchOptions { [[self window] setBackgroundColor:[UIColor whiteColor]]; // Override point for customization after application launch. return YES; } 

Aparentemente, no iOS7, há uma nova maneira de definir suas próprias transições personalizadas do UIViewController. Olhe nos documentos para UIViewControllerTransitioningDelegate. Além disso, aqui está um link para um artigo sobre isso: http://www.doubleencore.com/2013/09/ios-7-custom-transitions/

Encontrou outro excelente recurso para ajudar:

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

Usando o iOS7 TLTransitionAnimator para criar animações personalizadas

Votei a favor da resposta do @ Arne, porque considero a solução mais elegante para este problema. Eu gostaria apenas de adicionar algum código para responder ao problema do @ Bill a partir do seu comentário sobre a solução da @ Arne. Aqui está a citação do comentário:

Obrigado, isso funciona para mim. No entanto, quando o usuário toca no botão Voltar, ele reverte para a animação perdida (porque o botão Voltar não chama popViewControllerRetro). – Bill 03 de outubro às 12:36

Para chamar popViewControllerRetro quando o botão voltar é pressionado, há um pequeno hack que você pode executar para conseguir isso. Vá para o seu controlador de visualização, importe UIViewController + Retro.h e adicione este código em seu método viewWillDisappear:

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

Essa instrução if detectará quando o botão Voltar for pressionado e chamará popViewControllerRetro da class de categoria.

Cumprimentos.