ios - custom - transitions swift
UIPercentDrivenInteractiveTransition produciendo animación extraña cuando se hace (3)
Estoy usando una transición de inserción personalizada interactiva con un UIPercentDrivenInteractiveTransition
. El reconocedor de gestos llama con éxito a updateInteractiveTransition
del controlador de updateInteractiveTransition
. Del mismo modo, la animación se completa con éxito cuando llamo finishInteractiveTransition
del controlador de finishInteractiveTransition
.
Pero, a veces me sale un poco más de animación que me distrae al final (donde parece que se repite la última parte de la animación). Con animaciones razonablemente simples, rara vez veo este síntoma en el iPhone 5 (aunque rutinariamente lo veo en el simulador cuando trabajo en una computadora portátil lenta). Si hago que la animación sea más costosa computacionalmente (por ejemplo, muchas sombras, múltiples vistas animando diferentes direcciones, etc.), la frecuencia de este problema en el dispositivo aumenta.
¿Alguien más ha visto este problema y ha encontrado una solución que no sea la simplificación de las animaciones (que debo admitir que de todos modos) y / o escribir mis propios controladores de interacción? El enfoque UIPercentDrivenInteractiveTransition
tiene cierta elegancia, pero me inquieta el hecho de que se comporte de forma no determinista. ¿Han visto otros este comportamiento? ¿Alguien sabe de otras soluciones?
Para ilustrar el efecto, vea la imagen de abajo. Observe cómo la segunda escena, la vista roja, cuando termina la animación, parece repetir la última parte de su animación por segunda vez.
Esta animación es generada por:
llamando repetidamente a
updateInteractiveTransition
, avanzando la actualización del 0% al 40%;pausa momentánea (para que pueda diferenciar entre la transición interactiva y la animación de finalización resultante de
finishInteractiveTransition
);luego llamando a
finishInteractiveTransition
para completar la animación; yel bloque de
completion
la animación del controlador de animación llama a latransitionContext
completeTransition
para latransitionContext
, con el fin de limpiar todo.
Al hacer algunos diagnósticos, parece que es este último paso el que desencadena ese poco de animación extraña. El bloque de finalización del controlador de animación se llama cuando finaliza la animación, pero tan pronto como llamo completeTransition
, a veces repite el último bit de la animación (especialmente cuando se usan animaciones complejas).
No creo que sea relevante, pero este es mi código para configurar el controlador de navegación para realizar transiciones interactivas:
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationController.delegate = self;
self.interationController = [[UIPercentDrivenInteractiveTransition alloc] init];
}
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController*)fromVC
toViewController:(UIViewController*)toVC
{
if (operation == UINavigationControllerOperationPush)
return [[PushAnimator alloc] init];
return nil;
}
- (id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController*)navigationController
interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>)animationController
{
return self.interationController;
}
Mi PushAnimator
es:
@implementation PushAnimator
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext
{
return 5.0;
}
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
[[transitionContext containerView] addSubview:toViewController.view];
toViewController.view.frame = CGRectOffset(fromViewController.view.frame, fromViewController.view.frame.size.width, 0);;
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
toViewController.view.frame = fromViewController.view.frame;
} completion:^(BOOL finished) {
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}
@end
Tenga en cuenta que cuando coloco la declaración de registro en la que llamo completeTransition
, puedo ver que esta animación extraña ocurre después de que llamo completeTransition
(aunque la animación se realizó en ese momento). Esto sugeriría que esa animación adicional puede haber sido el resultado de la llamada para completeTransition
.
Para tu información, he hecho este experimento con un reconocedor de gestos:
- (void)handlePan:(UIScreenEdgePanGestureRecognizer *)gesture
{
CGFloat width = gesture.view.frame.size.width;
if (gesture.state == UIGestureRecognizerStateBegan) {
[self performSegueWithIdentifier:@"pushToSecond" sender:self];
} else if (gesture.state == UIGestureRecognizerStateChanged) {
CGPoint translation = [gesture translationInView:gesture.view];
[self.interactionController updateInteractiveTransition:ABS(translation.x / width)];
} else if (gesture.state == UIGestureRecognizerStateEnded ||
gesture.state == UIGestureRecognizerStateCancelled)
{
CGPoint translation = [gesture translationInView:gesture.view];
CGPoint velocity = [gesture velocityInView:gesture.view];
CGFloat percent = ABS(translation.x + velocity.x * 0.25 / width);
if (percent < 0.5 || gesture.state == UIGestureRecognizerStateCancelled) {
[self.interactionController cancelInteractiveTransition];
} else {
[self.interactionController finishInteractiveTransition];
}
}
}
También lo hice llamando a updateInteractiveTransition
y finishInteractiveTransition
manualmente (eliminando el reconocedor de gestos de la ecuación), y todavía muestra este extraño comportamiento:
[self performSegueWithIdentifier:@"pushToSecond" sender:self];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self.interactionController updateInteractiveTransition:0.40];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self.interactionController finishInteractiveTransition];
});
});
En conclusión, he llegado a la conclusión de que este es un problema aislado para UIPercentDrivenInteractiveTransition
con animaciones complejas. Puedo minimizar el problema simplificándolos (p. Ej., Instantáneas y vistas animadas instantáneas). También sospecho que podría resolver esto si no UIPercentDrivenInteractiveTransition
y escribo mi propio controlador de interacción, que haría la animación en sí, sin intentar interpolar el bloque animationWithDuration
.
Pero me preguntaba si alguien ha descubierto algún otro truco para usar UIPercentDrivenInteractiveTransition
con animaciones complejas.
El motivo de este error en mi caso fue establecer que el cuadro de la vista se animara varias veces. Solo estoy configurando el marco de vista UNA VEZ y solucioné mis problemas.
Entonces, en este caso, el cuadro de "toViewController.view" se estableció en DOS VECES, lo que hace que la animación tenga un comportamiento no deseado.
Este problema surge solo en el simulador.
SOLUCIÓN: self.interactiveAnimator.completionSpeed = 0.999;
error reportado aquí: http://openradar.appspot.com/14675246
He visto algo similar. Tengo dos soluciones posibles. Una es usar el rendimiento diferido en el controlador de finalización de animación:
} completion:^(BOOL finished) {
double delayInSeconds = 0.1;
dispatch_time_t popTime =
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
BOOL cancelled = [transitionContext transitionWasCancelled];
[transitionContext completeTransition:!cancelled];
});
self.interacting = NO;
}];
La otra posibilidad es: ¡no uses la animación de porcentajes! Nunca he tenido un problema como este al manejar manualmente la animación interactiva personalizada.