Подтвердить что ты не робот

UIPercentDrivenInteractiveTransition дает постороннюю анимацию, когда это делается

Я использую интерактивный пользовательский переход с помощью UIPercentDrivenInteractiveTransition. Устройство распознавания жестов успешно вызывает контроллер взаимодействия updateInteractiveTransition. Аналогично, анимация успешно завершается, когда я вызываю контроллер взаимодействия finishInteractiveTransition.

Но иногда я получаю дополнительный бит отвлекающей анимации в конце (где, похоже, повторяется вторая часть анимации). При достаточно простых анимациях я редко вижу этот симптом на iPhone 5 (хотя я регулярно вижу его на симуляторе при работе на медленном ноутбуке). Если сделать анимацию более дорогостоящей (т.е. Много теней, нескольких видов, анимационных разных направлениях и т.д.), Частота этой проблемы на устройстве увеличивается.

Кто-нибудь еще видел эту проблему и выяснил решение, отличное от оптимизации анимаций (что я, по общему признанию, должен делать в любом случае) и/или написания своих собственных контроллеров взаимодействия? Подход UIPercentDrivenInteractiveTransition имеет определенную элегантность, но мне неловко с тем, что он неверно ведет себя недетерминированно. Кто-нибудь видел это поведение? Кто-нибудь знает о других решениях?

Чтобы проиллюстрировать эффект, см. изображение ниже. Обратите внимание, что вторая сцена, красная точка, когда заканчивается анимация, повторяет вторую часть своей анимации второй раз.

animation not right

Эта анимация генерируется:

  • повторно вызывающий updateInteractiveTransition, прогрессирующее обновление от 0% до 40%;

  • кратковременно приостанавливается (поэтому вы можете различать интерактивный переход и анимацию завершения в результате finishInteractiveTransition);

  • затем вызов finishInteractiveTransition для завершения анимации; и

  • анимация контроллера анимации completion блокирует вызовы completeTransition для transitionContext, чтобы очистить все.

Выполняя некоторые диагностические операции, похоже, что именно этот последний шаг вызывает этот посторонний бит анимации. Блок завершения контроллера анимации вызывается, когда анимация завершена, но как только я вызываю completeTransition, он иногда повторяет последний бит анимации (особенно при использовании сложных анимаций).


Я не считаю это актуальным, но это мой код для настройки контроллера навигации для выполнения интерактивных переходов:

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

Мой 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

Обратите внимание, что когда я помещаю оператор регистрации, где я вызываю completeTransition, я вижу, что этот посторонний бит анимации происходит после того, как я вызываю completeTransition (даже если анимация действительно была выполнена в этой точке). Это предполагает, что эта дополнительная анимация могла быть результатом вызова completeTransition.

FYI, я сделал этот эксперимент с распознающим жестом:

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

Я также сделал это, вызвав updateInteractiveTransition и finishInteractiveTransition вручную (исключая распознаватель жестов из уравнения), и он по-прежнему демонстрирует это странное поведение:

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

В нижней строке, я пришел к выводу, что это проблема, изолированная от UIPercentDrivenInteractiveTransition сложными анимациями. Я могу свести к минимуму проблему, упростив их (например, снимки моментальных снимков и анимированные снимки). Я также подозреваю, что могу решить эту проблему, не используя UIPercentDrivenInteractiveTransition и записывая свой собственный контроллер взаимодействия, который бы сам выполнял анимацию, не пытаясь интерполировать блок animationWithDuration.

Но мне было интересно, придумали ли какие-либо другие трюки использовать UIPercentDrivenInteractiveTransition со сложными анимациями.

4b9b3361

Ответ 1

Я видел нечто подобное. У меня есть два возможных решения. Один из них - использовать задержанную производительность в обработчике завершения анимации:

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

Другая возможность: не используйте анимацию процента-драйва! У меня никогда не было такой проблемы, когда я вручную управлял интерактивной пользовательской анимацией.

Ответ 2

Эта проблема возникает только в симуляторе.

РЕШЕНИЕ: self.interactiveAnimator.completionSpeed ​​= 0.999;

ошибка здесь: http://openradar.appspot.com/14675246

Ответ 3

Причина этой ошибки в моем случае заключалась в том, что кадр анимации несколько раз. Я устанавливаю рамку просмотра только один раз, и он исправил мои проблемы.

Итак, в этом случае рамка "toViewController.view" была установлена ​​TWICE, что делает анимацию нежелательным поведением