tutorial logo español animacion after uiviewcontroller ios7 modalviewcontroller

logo - ¿Una solución alternativa para las animaciones personalizadas de UIViewController en el paisaje?



after effects tutorial español (5)

Tengo una transición animada de UIViewController personalizada, y parece que hay un error en iOS que daña el diseño en orientación horizontal. En el método principal de animación, me dan una combinación de vistas de paisajes y retratos. (En el retrato, las vistas son todas retratos, así que no hay problema).

- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext; { UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; UIView *containerView = [transitionContext containerView]; // fromViewController.view => landscape, transform // toViewController.view => portrait, transform // containerView => portrait, no transform [containerView addSubview:toViewController.view]; // ...animation... // }

Sé que la propiedad del frame no es confiable cuando una vista tiene una transformación, así que supongo que esta es la raíz del problema. En el modo horizontal, las vistas hacia y desde viewControllers tienen una transformación de 90 grados hacia la derecha [0 -1 1 0]. Intenté usar límites / centrar en el tamaño y posicionar la vista, además de eliminar la transformación y luego volver a aplicarla, pero UIKit me pelea e insiste en mostrar la vista como retrato. ¡Molesto!

En la captura de pantalla, el gris oscuro es el fondo de la ventana de UI, y el rojo es el controlador de vista modal agregado que debe cubrir toda la pantalla.

¿Alguien encontró una solución?


Ok, la solución es sorprendentemente simple:

Establezca el marco toViewController en el contenedor antes de agregar la vista al contenedor.

toViewController.view.frame = containerView.frame; [containerView addSubview:toViewController.view];

Actualización: Todavía hay una limitación en cuanto a que no se conoce la orientación del marco. Al principio es un retrato, pero se estira en el paisaje cuando se muestra en la pantalla. Si desea deslizar la vista desde la derecha, en el paisaje puede deslizarse desde la "parte superior" (o la parte inferior si se ve el otro paisaje).


La respuesta existente va en parte, pero no en todos los sentidos (queremos marcos adecuados y manejo de rotación en ambos dispositivos, todas las orientaciones, tanto para transiciones animadas como interactivas).

Esta publicación de blog ayuda:

http://www.brightec.co.uk/blog/ios-7-custom-view-controller-transitions-and-rotation-making-it-all-work

Y cita a un soporte de Apple que indica la verdadera naturaleza del problema:

"Para las transiciones de presentación personalizadas, configuramos una vista intermedia entre la ventana y la vista de Windows rootConController. Esta es la vista de contenedor en la que realiza su animación. Debido a un detalle de implementación de la rotación automática en iOS, cuando la interfaz gira, aplicamos un affine transfórmalo a la vista de Windows rootConController y modifica sus límites en consecuencia. Debido a que containerView hereda sus dimensiones de la ventana en lugar de la vista del controlador de la vista raíz, siempre está en la orientación vertical. "

"Si la animación de la presentación depende de la orientación del controlador de vista que se está presentando, deberá detectar la orientación del controlador de vista que se está presentando y modificar su animación adecuadamente. El sistema aplicará la transformación correcta al controlador de vista entrante, pero su animador necesita configura el marco del controlador de vista entrante ".

Pero no aborda las transiciones interactivas.

Desarrollé una solución completa al problema aquí:

https://github.com/alfiehanssen/Cards

Básicamente, debe calcular los marcos de sus viewControllers en función de la orientación de uno de los viewControllers (toViewController o fromViewController) en lugar de los límites de containerContext''s containerView.


Me quedé perplejo con este problema también. No me gustó demasiado la solución del interruptor / caja. Terminé creando esta función en su lugar:

@implementation UIView (Extras) - (CGRect)orientationCorrectedRect:(CGRect)rect { CGAffineTransform ct = self.transform; if (!CGAffineTransformIsIdentity(ct)) { CGRect superFrame = self.superview.frame; CGPoint transOrigin = rect.origin; transOrigin = CGPointApplyAffineTransform(transOrigin, ct); rect.origin = CGPointZero; rect = CGRectApplyAffineTransform(rect, ct); if (rect.origin.x < 0.0) { transOrigin.x = superFrame.size.width + rect.origin.x + transOrigin.x; } if (rect.origin.y < 0.0) { transOrigin.y = superFrame.size.height + rect.origin.y + transOrigin.y; } rect.origin = transOrigin; } return rect; } - (CGRect)orientationCorrectedRectInvert:(CGRect)rect { CGAffineTransform ct = self.transform; if (!CGAffineTransformIsIdentity(ct)) { ct = CGAffineTransformInvert(ct); CGRect superFrame = self.superview.frame; superFrame = CGRectApplyAffineTransform(superFrame, ct); CGPoint transOrigin = rect.origin; transOrigin = CGPointApplyAffineTransform(transOrigin, ct); rect.origin = CGPointZero; rect = CGRectApplyAffineTransform(rect, ct); if (rect.origin.x < 0.0) { transOrigin.x = superFrame.size.width + rect.origin.x + transOrigin.x; } if (rect.origin.y < 0.0) { transOrigin.y = superFrame.size.height + rect.origin.y + transOrigin.y; } rect.origin = transOrigin; } return rect; }

Básicamente, puede crear sus rectas de marcos utilizando las coordenadas vertical u horizontal, pero ejecútelas a través de la función con la transformación de la vista antes de aplicarla a la vista. Con este método, puede usar límites para obtener el tamaño de vista correcto.

CGRect endFrame = toViewController.view.frame; CGRect startFrame = endFrame; startFrame.origin.y = fromViewController.view.bounds.size.height; endFrame = [fromViewController.view orientationCorrectedRect:endFrame]; startFrame = [fromViewController.view orientationCorrectedRect:startFrame]; toViewController.view.frame = startFrame;


Una solución es tener una transición muy corta (o cero segundos), y una vez que la transición haya finalizado y se presente su controlador de vista, se le aplicarán las transformaciones correctas. A continuación, realiza tus animaciones desde el propio controlador de vista presentado.


Me encontré con este problema y simplemente no creo que las soluciones anteriores le hagan justicia. Propongo una solución que no requiere código hacky y marcos codificados.

UIView tiene una función increíble para convertir un CGRect en el espacio de coordenadas de otro (es decir; +[UIView convertRect:fromView:] ). Así que quiero detallar de una manera mucho más simple que uno puede lograr este efecto en cualquier orientación sin ningún valor codificado. En este ejemplo, digamos que queremos una animación simple que deslice una vista desde la derecha de la pantalla.

Entonces, en la animateTransition(:) nuestro animador animateTransition(:) podríamos simplemente realizar lo siguiente:

Rápido

func animateTransition(transitionContext: UIViewControllerContextTransitioning) { let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)! let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)! let toView = toViewController.view let fromView = fromViewController.view let containerView = transitionContext.containerView() if(isPresenting) { //now we want to slide in from the right let startingRect = CGRectOffset(fromView.bounds, CGRectGetWidth(fromView.bounds), 0) toView.frame = containerView.convertRect(startingRect, fromView:fromView); containerView.addSubview(toView) let destinationRect = containerView.convertRect(fromView.bounds, fromView: fromView) UIView.animateWithDuration(transitionDuration(transitionContext), delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.7, options: .BeginFromCurrentState, animations: { () -> Void in toView.frame = destinationRect }, completion: { (complete) -> Void in transitionContext.completeTransition(!transitionContext.transitionWasCancelled()) }) } else { //we want to slide out to the right let endingRect = containerView.convertRect(CGRectOffset(fromView.bounds, CGRectGetWidth(fromView.bounds), 0), fromView: fromView) UIView.animateWithDuration(transitionDuration(transitionContext), delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.7, options: .BeginFromCurrentState, animations: { () -> Void in fromView.frame = endingRect }, completion: { (complete) -> Void in if !transitionContext.transitionWasCancelled() { fromView.removeFromSuperview() } transitionContext.completeTransition(!transitionContext.transitionWasCancelled()) }) } }

C objetivo

UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; UIView *toView = toViewController.view; UIView *fromView = fromViewController.view; UIView *containerView = [transitionContext containerView]; if(self.isPresenting) { //now we want to slide in from the right CGRect startingRect = CGRectOffset(fromView.bounds, CGRectGetWidth(fromView.bounds), 0); toView.frame = [containerView convertRect:startingRect fromView:fromView]; [containerView addSubview:toView]; [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{ toView.frame = [containerView convertRect:fromView.bounds fromView:fromView]; } completion:^(BOOL finished) { [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; }]; } else { //we want to slide out to the right [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{ CGRect endingRect = CGRectOffset(fromView.bounds, CGRectGetWidth(fromView.bounds), 0); fromView.frame = [containerView convertRect:endingRect fromView:fromView]; } completion:^(BOOL finished) { [fromView removeFromSuperview]; [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; }]; }

Espero que esto ayude a alguien más que vino aquí en el mismo barco (si lo hace, un voto positivo no va a doler :))