UIPercentDrivenInteractiveTransition produzindo animação estranha quando concluído

StackOverflow https://stackoverflow.com//questions/23047350

  •  21-12-2019
  •  | 
  •  

Pergunta

Estou usando uma transição push personalizada interativa com um UIPercentDrivenInteractiveTransition.O reconhecedor de gestos chama com sucesso o controlador de interação updateInteractiveTransition.Da mesma forma, a animação é concluída com sucesso quando eu chamo o controlador de interação finishInteractiveTransition.

Mas, às vezes, recebo um pouco mais de animação perturbadora no final (onde parece repetir a última parte da animação).Com animações razoavelmente simples, raramente vejo esse sintoma no iPhone 5 (embora eu o veja rotineiramente no simulador ao trabalhar em um laptop lento).Se eu tornar a animação mais cara computacionalmente (por exemplomuitas sombras, múltiplas visualizações animando diferentes direções, etc.), a frequência desse problema no dispositivo aumenta.

Alguém mais viu esse problema e descobriu uma solução diferente de simplificar as animações (o que eu deveria fazer de qualquer maneira) e/ou escrever meus próprios controladores de interação?O UIPercentDrivenInteractiveTransition abordagem tem uma certa elegância, mas estou desconfortável com o fato de que ela se comporta mal de forma não determinística.Outras pessoas viram esse comportamento?Alguém conhece outras soluções?

Para ilustrar o efeito, veja a imagem abaixo.Observe como a segunda cena, a vista vermelha, quando a animação termina, parece repetir a última parte da animação uma segunda vez.

animation not right

Esta animação é gerada por:

  • ligando repetidamente updateInteractiveTransition, progredindo atualização de 0% a 40%;

  • pausando momentaneamente (para que você possa diferenciar entre a transição interativa e a animação de conclusão resultante de finishInteractiveTransition);

  • então ligando finishInteractiveTransition para completar a animação;e

  • a animação do controlador de animação completion bloquear chamadas completeTransition para o transitionContext, para limpar tudo.

Fazendo alguns diagnósticos, parece que é esta última etapa que aciona aquela animação estranha.O bloco de conclusão do controlador de animação é chamado quando a animação termina, mas assim que eu chamo completeTransition, às vezes ele repete a última parte da animação (principalmente ao usar animações complexas).


Não creio que seja relevante, mas este é o meu código para configurar o controlador de navegação para realizar transições interativas:

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

Meu PushAnimator é:

@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

Observe, quando coloco a instrução de log onde chamo completeTransition, posso ver que essa animação estranha acontece depois que eu ligo completeTransition (mesmo que a animação tenha sido realmente feita naquele ponto).Isto sugeriria que essa animação extra pode ter sido resultado da chamada para completeTransition.

Para sua informação, fiz este experimento com um reconhecedor 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];
        }
    }
}

Eu também fiz isso ligando para o updateInteractiveTransition e finishInteractiveTransition manualmente (eliminando o reconhecedor de gestos da equação), e ainda exibe este comportamento estranho:

[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];
    });
});

Resumindo, concluí que este é um problema isolado para UIPercentDrivenInteractiveTransition com animações complexas.Posso minimizar o problema simplificando-os (por ex.instantâneos e visualizações instantâneas animadas).Eu também suspeito que poderia resolver isso não usando UIPercentDrivenInteractiveTransition e escrever meu próprio controlador de interação, que faria a animação sozinho, sem tentar interpolar o animationWithDuration bloquear.

Mas eu queria saber se alguém descobriu algum outro truque para usar UIPercentDrivenInteractiveTransition com animações complexas.

Foi útil?

Solução

Eu vi algo semelhante.Eu tenho duas soluções possíveis.Uma é usar o desempenho atrasado no manipulador de conclusão da animação:

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

A outra possibilidade é:não use animação percentual!Eu tenho nunca tive um problema como este ao conduzir a animação personalizada interativa eu mesmo manualmente.

Outras dicas

Este problema surge apenas no simulador.

SOLUÇÃO:self.interactiveAnimator.completionSpeed ​​= 0,999;

bug relatado aqui: http://openradar.appspot.com/14675246

O motivo desse erro no meu caso foi definir o quadro da visualização animada várias vezes.Estou configurando o quadro de visualização apenas UMA VEZ e isso resolveu meus problemas.

Então neste caso, o frame de "toViewController.view" foi definido DUAS VEZES, fazendo com que a animação tivesse um comportamento indesejado

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top