Repository: airbnb/lottie-ios
File: Sources/Public/Animation/AnimationView.swift (Swift)

Code before:

  /// Returns the current animation frame while an animation is playing.
  public var realtimeAnimationFrame: AnimationFrameTime {
    isAnimationPlaying ? animationLayer?.presentation()?.currentFrame ?? currentFrame : currentFrame
  }

  /// Returns the current animation frame while an animation is playing.
  public var realtimeAnimationProgress: AnimationProgressTime {
    if let animation = animation {
      return animation.progressTime(forFrame: realtimeAnimationFrame)
    }
    return 0
  }

  /// Sets the speed of the animation playback. Defaults to 1
  public var animationSpeed: CGFloat = 1 {
    didSet {
      updateInFlightAnimation()
    }
  }

  /**
   When `true` the animation will play back at the framerate encoded in the
   `Animation` model. When `false` the animation will play at the framerate
   of the device.

   Defaults to false
   */
  public var respectAnimationFrameRate: Bool = false {
    didSet {
      animationLayer?.respectAnimationFrameRate = respectAnimationFrameRate
    }
  }

  /**
    Controls the cropping of an Animation. Setting this property will crop the animation
    to the current views bounds by the viewport frame. The coordinate space is specified
    in the animation's coordinate space.

    Animatable.
   */
  public var viewportFrame: CGRect? = nil {
    didSet {

      /*
       This is really ugly, but is needed to trigger a layout pass within an animation block.
       Typically this happens automatically, when layout objects are UIView based.
       The animation layer is a CALayer which will not implicitly grab the animation
       duration of a UIView animation block.

       By setting bounds and then resetting bounds the UIView animation block's

Review comment (suggestion):
Calling `removeCurrentAnimation()` before `updateAnimationFrame(...)` is unnecessary for the Core Animation engine, but causes unnecessary animation setup passes (since it sets the `currentFrame` to `0`)

Code after:
   */
  public var currentTime: TimeInterval {
    set {
      if let animation = animation {
        currentFrame = animation.frameTime(forTime: newValue)
      } else {
        currentFrame = 0
      }
    }
    get {
      if let animation = animation {
        return animation.time(forFrame: currentFrame)
      } else {
        return 0
      }
    }
  }

  /**
   Sets the current animation time with a frame in the animations framerate.

   Note: Setting this will stop the current animation, if any.
   */
  public var currentFrame: AnimationFrameTime {
    set {
      removeCurrentAnimationIfNecessary()
      updateAnimationFrame(newValue)
    }
    get {
      animationLayer?.currentFrame ?? 0
    }
  }

  /// Returns the current animation frame while an animation is playing.
  public var realtimeAnimationFrame: AnimationFrameTime {
    isAnimationPlaying ? animationLayer?.presentation()?.currentFrame ?? currentFrame : currentFrame
  }

  /// Returns the current animation frame while an animation is playing.
  public var realtimeAnimationProgress: AnimationProgressTime {
    if let animation = animation {
      return animation.progressTime(forFrame: realtimeAnimationFrame)
    }
    return 0
  }

  /// Sets the speed of the animation playback. Defaults to 1
  public var animationSpeed: CGFloat = 1 {
    didSet {
      updateInFlightAnimation()
    }