Есть ли способ наблюдать изменения фракции в UIViewPropertyAnimator

Я смотрел на очень крутой новый UIViewPropertyAnimator класс в iOS 10. Он позволяет легко делать такие вещи, как пауза, возобновление и обратная анимация UIView в полете. Раньше вам приходилось манипулировать базовыми CAAnimations, созданными системой, чтобы делать это с анимациями UIView.

Новый UIViewPropertyAnimator класс имеет свойство fractionComplete, Он варьируется от 0,0 (начало анимации) до 1,0 (конец анимации.) Если вы измените значение, вы можете "очистить" анимацию от начала до конца.

У меня есть демонстрационный проект на Github под названием KeyframeViewAnimations, который позволяет использовать ползунок для очистки UIView и CAAnimations назад и вперед с использованием довольно загадочных трюков CAAnimation. При запуске анимации ползунок перемещается от начала к концу, чтобы показать ход анимации. Этот проект был написан в Objective-C до выпуска Swift, но основные методы такие же, как в Objective-C или Swift.

Я решил создать эквивалентный проект, используя UIViewPropertyAnimator, Есть некоторые причуды, но это довольно просто. Одна вещь, которую я не мог понять, как это сделать чисто - это наблюдать за ходом анимации. fractionComplete свойство, чтобы я мог обновить ползунок в процессе анимации. Я попытался настроить KVO (наблюдение значения ключа) на fractionComplete свойство, но оно не вызывает уведомление KVO, пока анимация не будет завершена.

В итоге я настроил таймер, который работает с очень небольшим интервалом и запрашивает UIViewPropertyAnimator"s fractionComplete свойство неоднократно и обновляя ползунок по мере его продвижения. Это работает, но это не очень чистый способ делать вещи. Было бы намного лучше, если бы был способ получать уведомления о ходе анимации.

Я надеюсь, что что-то мне не хватает.

Вы можете увидеть UIViewPropertyAnimator на основе проекта на Github по этой ссылке: UIViewPropertyAnimator-test.

Код, который получает значение прогресса от аниматора, выглядит следующим образом:

func startTimer(_ start: Bool) {
  if start {
    timer = Timer.scheduledTimer(withTimeInterval: 0.02,
     repeats: true) {
        timer in
        var value = Float(self.viewAnimator.fractionComplete)
        if self.animatingBackwards {
          value = 1 - value
        }
        self.animationSlider.value = value
     }
  }
  else {
    self.timer?.invalidate()
  }
}

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

2 ответа

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

Вы пытались создать подкласс UIViewPropertyAnimator, а затем переопределить свойство fractionComplete?

class MyPropertyAnimator : UIViewPropertyAnimator {
    override var fractionComplete: CGFloat {
        didSet {
            print("didSetFraction")
        }
    }
}
Другие вопросы по тегам