Ошибка анимации iOS 8

У меня есть простой метод для просмотра анимации.

-(void)animateSelf
{
    CABasicAnimation * animation;

    animation = [CABasicAnimation animationWithKeyPath:@"position.y"];
    // settings ...
    [self.view.layer addAnimation:animation forKey:@"position.y"];

    animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    // settings ...
    [self.view.layer addAnimation:animation forKey:@"transform.rotation.z"];

    [UIView animateWithDuration: 1.0 animations:^{
        CGRect rect = self.view.frame;
        rect.origin.y += 800;
        self.view.frame = rect;
    } completion:nil];
}

Для iOS 7 это работало хорошо. Но для iOS 8 анимация ведет себя непредсказуемо. Есть ли способ объединить эти анимации для iOS 8?

Я пытался заменить animateWithDuration: другой CABasicAnimation, но это не помогло. Журналы view.frame верны, но анимация view.frame выпрыгивает из неясного источника.

После удаления CABasicAnimation для position.y (первый) ошибка исчезла.

4 ответа

У вас есть три анимации:

  1. Вы оживляете слой position
  2. Вы оживляете слой transform
  3. Вы оживляете представление frame который в свою очередь оживляет слой position,

Анимации 1 и 3 сталкиваются.

  • На iOS 7 такое поведение, что анимация 3 отменяет анимацию 1.
  • На iOS 8 поведение заключается в том, что анимации 1 и 3 запускаются одновременно ("Аддитивные анимации").

Я предлагаю вам просто удалить анимацию 1, а также посмотреть соответствующее видео WWDC 2014 (я думаю, что это было Building Interruptible and Responsive Interactions).

Для меня работало отключение автолайтов на представлении и ПОДКЛЮЧЕНИЯ к представлению, которое я анимировал в какой-то момент перед анимацией. Отключение автопутешествий из раскадровки было недостаточно в iOS8.

[viewToAnimate removeFromSuperview];
[viewToAnimate setTranslatesAutoresizingMaskIntoConstraints:YES];
//addSubview again at original index
[superView insertSubview:viewToAnimate atIndex:index];

Этот пример может помочь вам, я хотел бы открыть его раньше, чем потратить часы. Вместо того, чтобы оживить frameоживляет ее contraints, Нажмите на ограничение автоматического размещения, которое вы хотите настроить (в конструкторе интерфейса, например, ограничение сверху). Затем сделайте это IBOutlet;

@property (strong, nonatomic) IBOutlet NSLayoutConstraint *topConstraint;

Оживить вверх;

self.topConstraint.constant = -100;    
[self.viewToAnimate setNeedsUpdateConstraints]; 
[UIView animateWithDuration:1.5 animations:^{
    [self.viewToAnimate layoutIfNeeded]; 
}];

Оживить обратно в исходное место

self.topConstraint.constant = 0;    
[self.viewToAnimate setNeedsUpdateConstraints];  
[UIView animateWithDuration:1.5 animations:^{
    [self.viewToAnimate layoutIfNeeded];
}];

Первоначально опубликовано мной здесь

Таким образом, вы бы скорректировать ограничение для self.view.frame в вашем примере.

У меня также возникла небольшая неприятная разница между анимацией iOS7 и iOS8. В большинстве случаев это было сломано, это было либо:

  • единственная комбинация Scale, Transform и Rotate CGAffineTransforms - результат зависел от версии iOS
  • или сложная последовательность анимаций на разных видах - некоторые виды "сбрасывали" свои позиции перед началом новой части анимации. Около 5% частей анимации были затронуты.

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

То, что оказалось универсальным решением для обеих проблем, - это поместить проблемные виды в представление-оболочку и использовать его для разделения анимации вращения или создания анимации, которая вызывает эффект "сброса". Теперь он работает одинаково в 7.1.1 и 8.1.1.

Другие вопросы по тегам