tab guidelines bar ios cocoa-touch custom-transition

guidelines - tab bar ios



Animación de transición personalizada del controlador de navegación (4)

Es posible que desee agregar el siguiente código antes de agregar

toViewController.view.frame = [transitionContext finalFrameForViewController:toViewController];

De otra pregunta custom-transition-for-push-animation-with-navigationcontroller-on-ios-9

De la documentación de Apple para finalFrameForViewController:

Devuelve el rectángulo del cuadro final para la vista del controlador de vista especificado.

El rectángulo devuelto por este método representa el tamaño de la vista correspondiente al final de la transición. Para la vista que se cubre durante la presentación, el valor devuelto por este método podría ser CGRectZero pero también podría ser un rectángulo de marco válido.

He estado siguiendo algunos tutoriales para crear animaciones personalizadas durante la transición de una vista a otra.

Mi proyecto de prueba usando segue personalizado desde here funciona bien, pero alguien me dijo que ya no se recomienda hacer animación personalizada dentro de un segue personalizado, y debería usar UIViewControllerAnimatedTransitioning .

Seguí varios tutoriales que hacen uso de este protocolo, pero todos tratan sobre la presentación modal (por ejemplo, este tutorial ).

Lo que estoy tratando de hacer es una segmentación de inserción dentro de un árbol controlador de navegación, pero cuando trato de hacer lo mismo con una segmentación de presentación (inserción) ya no funciona.

Indíqueme la forma correcta de hacer una animación de transición personalizada de una vista a otra en un controlador de navegación.

¿Y de todos modos puedo usar un método para todas las animaciones en transición? Sería incómodo si algún día quisiera hacer la misma animación pero terminar duplicando el código dos veces para trabajar en la transición modal vs controlador.


Para hacer una transición personalizada con el controlador de navegación ( UINavigationController ), debe:

  • Defina su controlador de vista para cumplir con el protocolo UINavigationControllerDelegate . Por ejemplo, puede tener una extensión de clase privada en el archivo .m su controlador de vista que especifique la conformidad con este protocolo:

    @interface ViewController () <UINavigationControllerDelegate> @end

  • Asegúrese de especificar realmente su controlador de vista como delegado de su controlador de navegación:

    - (void)viewDidLoad { [super viewDidLoad]; self.navigationController.delegate = self; }

  • Implemente animationControllerForOperation en su controlador de vista:

    - (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController*)fromVC toViewController:(UIViewController*)toVC { if (operation == UINavigationControllerOperationPush) return [[PushAnimator alloc] init]; if (operation == UINavigationControllerOperationPop) return [[PopAnimator alloc] init]; return nil; }

  • Implemente animadores para animaciones push y pop, por ejemplo:

    @interface PushAnimator : NSObject <UIViewControllerAnimatedTransitioning> @end @interface PopAnimator : NSObject <UIViewControllerAnimatedTransitioning> @end @implementation PushAnimator - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext { return 0.5; } - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext { UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; [[transitionContext containerView] addSubview:toViewController.view]; toViewController.view.alpha = 0.0; [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{ toViewController.view.alpha = 1.0; } completion:^(BOOL finished) { [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; }]; } @end @implementation PopAnimator - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext { return 0.5; } - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext { UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; [[transitionContext containerView] insertSubview:toViewController.view belowSubview:fromViewController.view]; [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{ fromViewController.view.alpha = 0.0; } completion:^(BOOL finished) { [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; }]; } @end

    Eso hace que la transición se desvanezca, pero puede personalizar la animación como mejor le parezca.

  • Si desea manejar gestos interactivos (por ejemplo, algo como el deslizamiento nativo de izquierda a derecha para hacer estallar), debe implementar un controlador de interacción:

    • Defina una propiedad para un controlador de interacción (un objeto que se ajuste a UIViewControllerInteractiveTransitioning ):

      @property (nonatomic, strong) UIPercentDrivenInteractiveTransition *interactionController;

      Este UIPercentDrivenInteractiveTransition es un buen objeto que hace el trabajo pesado de actualizar su animación personalizada en función de qué tan completo es el gesto.

    • Agregue un reconocedor de gestos a su vista. Aquí solo estoy implementando el reconocedor de gestos izquierdo para simular un pop:

      UIScreenEdgePanGestureRecognizer *edge = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipeFromLeftEdge:)]; edge.edges = UIRectEdgeLeft; [view addGestureRecognizer:edge];

    • Implemente el controlador de reconocimiento de gestos:

      /** Handle swipe from left edge * * This is the "action" selector that is called when a left screen edge gesture recognizer starts. * * This will instantiate a UIPercentDrivenInteractiveTransition when the gesture starts, * update it as the gesture is "changed", and will finish and release it when the gesture * ends. * * @param gesture The screen edge pan gesture recognizer. */ - (void)handleSwipeFromLeftEdge:(UIScreenEdgePanGestureRecognizer *)gesture { CGPoint translate = [gesture translationInView:gesture.view]; CGFloat percent = translate.x / gesture.view.bounds.size.width; if (gesture.state == UIGestureRecognizerStateBegan) { self.interactionController = [[UIPercentDrivenInteractiveTransition alloc] init]; [self popViewControllerAnimated:TRUE]; } else if (gesture.state == UIGestureRecognizerStateChanged) { [self.interactionController updateInteractiveTransition:percent]; } else if (gesture.state == UIGestureRecognizerStateEnded) { CGPoint velocity = [gesture velocityInView:gesture.view]; if (percent > 0.5 || velocity.x > 0) { [self.interactionController finishInteractiveTransition]; } else { [self.interactionController cancelInteractiveTransition]; } self.interactionController = nil; } }

    • En su delegado de controlador de navegación, también debe implementar interactionControllerForAnimationController método de delegado de interactionControllerForAnimationController

      - (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController { return self.interactionController; }

Si buscas en Google el "tutorial de transición personalizado UINavigationController" y obtendrás muchos resultados. O vea el video WWDC 2013 Transiciones personalizadas .


Usando las respuestas perfectas de Rob & Q i, aquí está el código simplificado de Swift, usando la misma animación de desvanecimiento para .push y .pop:

extension YourViewController: UINavigationControllerDelegate { func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { //INFO: use UINavigationControllerOperation.push or UINavigationControllerOperation.pop to detect the ''direction'' of the navigation class FadeAnimation: NSObject, UIViewControllerAnimatedTransitioning { func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 0.5 } func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) if let vc = toViewController { transitionContext.finalFrame(for: vc) transitionContext.containerView.addSubview(vc.view) vc.view.alpha = 0.0 UIView.animate(withDuration: self.transitionDuration(using: transitionContext), animations: { vc.view.alpha = 1.0 }, completion: { finished in transitionContext.completeTransition(!transitionContext.transitionWasCancelled) }) } else { NSLog("Oops! Something went wrong! ''ToView'' controller is nill") } } } return FadeAnimation() } }

No olvide establecer el delegado en el método viewDidLoad () de YourViewController:

override func viewDidLoad() { //... self.navigationController?.delegate = self //... }


Funciona tanto swift 3 como 4

@IBAction func NextView(_ sender: UIButton) { let newVC = self.storyboard?.instantiateViewControllerWithIdentifier(withIdentifier: "NewVC") as! NewViewController let transition = CATransition() transition.duration = 0.5 transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) transition.type = kCATransitionPush transition.subtype = kCAGravityLeft //instead "kCAGravityLeft" try with different transition subtypes self.navigationController?.view.layer.add(transition, forKey: kCATransition) self.navigationController?.pushViewController(newVC, animated: false) }