UIViewController: problema con la transición de descarte personalizada
Tengo un contenido UIViewController que presenta una configuración UIViewController usando una transición personalizada. La presentación es conpresentViewController:animated:completion:
.
Cuando más tarde descarte la configuración condismissViewControllerAnimated:completion:
, el controlador de presentación salta repentinamente a su posición inicial antes de la presentación del controlador de configuración.
Tengo una solución para esto en el dispositivo pero no en el simulador. Sin embargo, me gustaría saber qué estoy haciendo mal en lugar de piratear un cuerpo que lo hace desaparecer. También planeo hacer que esta animación sea interactiva, y sospecho que estos problemas se amplificarán cuando haga esto.
Transición personalizada: apertura del capóEl efecto deseado es que elpresentación el controlador se desliza hacia abajo en la pantalla y elpresentado Se ve que el controlador yace detrás de él desde donde se levanta para llenar la pantalla. La parte superior del controlador presentador permanece en pantalla durante la vida útil del uso del controlador presentado. Se queda en la parte inferior de la pantalla, peroencima El controlador presentado.
Puede imaginar levantar el capó de un automóvil (el controlador de presentación frontal) para ver el motor detrás (la configuración presentada), pero el capó permanece visible en la parte inferior por un poco de contexto.
Planeo refinar esto para que el controlador de presentación realmente parezca elevarse con perspectiva en una forma 3d, pero aún no he llegado tan lejos.
Cuando se descartan las configuraciones, el controlador presentador original (capó) debe deslizarse hacia atrás en la pantalla y el controlador presentado (configuraciones) se hunde ligeramente (cerrando el capó).
CódigoEste es el método que activa y desactiva la configuración de la pantalla (solo se llama mediante un UIButton). Notará que el controlador de vista de presentación se configura como el<UIViewControllerTransitioningDelegate>
.
-(void) toggleSettingsViewController
{
const BOOL settingsAreShowing = [self presentedViewController] != nil;
if(!settingsAreShowing)
{
UIViewController *const settingsController = [[self storyboard] instantiateViewControllerWithIdentifier: @"STSettingsViewController"];
[settingsController setTransitioningDelegate: self];
[settingsController setModalPresentationStyle: UIModalPresentationCustom];
[self presentViewController: settingsController animated: YES completion: nil];
}
else
{
[self dismissViewControllerAnimated: YES completion: nil];
}
}
Para implementar<UIViewControllerAnimatedTransitioning>
el controlador de vista de presentación también solo se devuelve como el<UIViewControllerAnimatedTransitioning>
-(id<UIViewControllerAnimatedTransitioning>) animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
{
return self;
}
-(id<UIViewControllerAnimatedTransitioning>) animationControllerForDismissedController:(UIViewController *)dismissed
{
// Test Point 1.
return self;
}
Finalmente, el controlador de vista de presentación recibiráanimateTransition:
:
-(void) animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIViewController *const fromController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *const toController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
const BOOL isUnwinding = [toController presentedViewController] == fromController;
const BOOL isPresenting = !isUnwinding;
UIViewController * presentingController = isPresenting ? fromController : toController;
UIViewController * presentedController = isPresenting ? toController : fromController;
if(isPresenting)
{
// Add the presented controller (settings) to the view hierarchy _behind_ the presenting controller.
[[transitionContext containerView] insertSubview: [presentedController view] belowSubview: [presentingController view]];
// Set up the initial position of the presented settings controller. Scale it down so it seems in the distance. Alpha it down so it is dark and shadowed.
presentedController.view.transform = CGAffineTransformMakeScale(0.9, 0.9);
presentedController.view.alpha = 0.7;
[UIView animateWithDuration: [self transitionDuration: transitionContext] animations:^{
// Lift up the presented controller.
presentedController.view.transform = CGAffineTransformMakeScale(1.0, 1.0);
// Brighten the presented controller (out of shadow).
presentedController.view.alpha = 1;
// Push the presenting controller down the screen – 3d effect to be added later.
presentingController.view.layer.transform = CATransform3DMakeTranslation(0,400,0);
} completion: ^(BOOL finished){
[transitionContext completeTransition: ![transitionContext transitionWasCancelled]];
}];
}
else
{
// Test Point 2.
// !!!This line should not be needed!!!
// It resets the presenting controller to where it ought to be anyway.
presentingController.view.layer.transform = CATransform3DMakeTranslation(0,400,0);
[UIView animateWithDuration: [self transitionDuration: transitionContext] animations:^{
// Bring the presenting controller back to its original position.
presentingController.view.layer.transform = CATransform3DIdentity;
// Lower the presented controller again and put it back in to shade.
presentedController.view.transform = CGAffineTransformMakeScale(0.9, 0.9);
presentedController.view.alpha = 0.4;
} completion:^(BOOL finished) {
[transitionContext completeTransition: ![transitionContext transitionWasCancelled]];
}];
}
}
-(NSTimeInterval) transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
return 0.5;
}
ProblemaEn el código anterior, he indicado¡¡¡Esta línea no debería ser necesaria !!!.
Lo que pasa es que entrePunto de prueba 1 yPunto de prueba 2 la posición de la pantalla del controlador de vista de presentación se restablece para ser los límites predeterminados de pantalla completa. Por lo tanto, en lugar de estar en la parte inferior de la pantalla lista para animar una copia de seguridad de nuevo sin problemas, de repente salta hacia arriba para posicionar que también debe animar sin problemas.
He intentado varios enfoques para animar el controlador de vista de presentación en la pantalla:
He cambiado el marco de su vista.He cambiado la transformación de su vista.He cambiado la transformación 3d de la capa de su vista.En todos los casos, aPunto de prueba 1, cuando se solicita al delegado de transición, el controlador de presentación se configura como yo esperaría. Sin embargo, en todos los casos, enPunto de prueba 2, el controlador de vista de presentación ha perdido la posición correcta y se ha "borrado" para tener la posición normal de pantalla completa a la que quiero animarlo.
En el trabajo anterior, reubico explícitamente el controlador de vista de presentación de nuevo a donde debería estar al comienzo de la animación con¡¡¡Esta línea no debería ser necesaria !!!. Esto parece funcionar en el dispositivo con la versión actual de iOS 7. Sin embargo, en el simulador, el controlador es visible en la posición despejada durante al menos un fotograma.
Sospecho que estoy haciendo algo mal y que me voy a meter en problemas con mi solución simplemente enmascarando otro problema.
¿Alguna idea de qué está pasando? ¡Gracias!