iOS эквивалент Androids ValueAnimator - PullRequest
0 голосов
/ 04 мая 2020

Я хотел бы что-то, что имитирует поведение в iOS из ValueAnimator в Android. В обычных условиях я бы использовал UIView анимацию, но, к сожалению, значение объектов, которое я пытаюсь интерполировать с течением времени, не работает с обычной анимацией.

В моем конкретном случае я использую Lottie анимацию и пытаюсь изменить ход анимации с помощью UIView анимации, но вместо анимации, изменяющей значение прогресса с течением времени, он просто переходит к конечному значению. Например:

let lottieAnim = ...
lottieAnim.animationProgress = 0

UIView.animate(withDuration: 2) {
    lottieAnim.animationProgress = 1
}

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

Мне нужно что-то, что периодически обновляется, чтобы mimi c анимация, первое, что приходит на ум, это Android ValueAnimator class.

1 Ответ

0 голосов
/ 04 мая 2020

Я собрал класс, который будет немного имитировать c a ValueAnimator из android и позволит вам при необходимости указать собственную кривую анимации (по умолчанию это просто линейный)

Простое использование

let valueAnimator = ValueAnimator(duration: 2) { value in
  animationView.animationProgress = value
}

valueAnimator.start()

Расширенное использование

let valueAnimator = ValueAnimator(from: 0, to: 100, duration: 60, animationCurveFunction: { time, duration in
  return atan(time)*2/Double.pi
}, valueUpdater: { value in
  animationView.animationProgress = value
})

valueAnimator.start()

Вы также можете отменить его в любой момент, используя:

valueAnimator.cancel()

Значение Класс аниматора в Swift 5

// swiftlint:disable:next private_over_fileprivate
fileprivate var defaultFunction: (TimeInterval, TimeInterval) -> (Double) = { time, duration in
  return time / duration
}

class ValueAnimator {

  let from: Double
  let to: Double
  var duration: TimeInterval = 0
  var startTime: Date!
  var displayLink: CADisplayLink?
  var animationCurveFunction: (TimeInterval, TimeInterval) -> (Double)
  var valueUpdater: (Double) -> Void

  init (from: Double = 0, to: Double = 1, duration: TimeInterval, animationCurveFunction: @escaping (TimeInterval, TimeInterval) -> (Double) = defaultFunction, valueUpdater: @escaping (Double) -> Void) {
    self.from = from
    self.to = to
    self.duration = duration
    self.animationCurveFunction = animationCurveFunction
    self.valueUpdater = valueUpdater
  }

  func start() {
    displayLink = CADisplayLink(target: self, selector: #selector(update))
    displayLink?.add(to: .current, forMode: .default)
  }

  @objc
  private func update() {

    if startTime == nil {
      startTime = Date()
      valueUpdater(from + (to - from) * animationCurveFunction(0, duration))
      return
    }

    var timeElapsed = Date().timeIntervalSince(startTime)
    var stop = false

    if timeElapsed > duration {
      timeElapsed = duration
      stop = true
    }

    valueUpdater(from + (to - from) * animationCurveFunction(timeElapsed, duration))

    if stop {
      cancel()
    }
  }

  func cancel() {
    self.displayLink?.remove(from: .current, forMode: .default)
    self.displayLink = nil
  }
}

Возможно, вы могли бы улучшить это, чтобы быть более обобщенным c, но это служит моей цели.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...