Lottie-ios: Monitoring current frame changes in iOS?

Created on 13 Sep 2018  路  2Comments  路  Source: airbnb/lottie-ios

This issue is a:

  • [] Feature Request

What Platform are you on?

  • [] iOS

Expected Behavior

It would be nice to be able to monitor when a LOTAnimationView's current frame changes, to sync other events with the change. It seems this may be possible using a callback block on a known element in the animation but that is a bit overkill. I apologize if I've missed this and it already exists.

Essentially something like:

let animationView = LOTAnimationView(...)
animationView.onFrameChange = { (currentFrame, currentProgress, currentTime) in
   print("The animation is now on \(currentFrame)")
}

Or via some kind of delegate:

let animationView = LOTAnimationView(...)
animationView.stateChangeDelegate = self

/// LOTAnimationViewStateDelegate

func animationView(_ animationView: LOTAnimationView, didChangeCurrentFrame currentFrame: Int) {
}

func didStartPlayingAnimationView(_ animationView: LOTAnimationView) {
}

func didStopPlayingAnimationView(_ animationView: LOTAnimationView) {
}

Actual Behavior

There doesn't appear to be a non-trivial way of accomplishing this.

Most helpful comment

After further investigation it appears this is pretty trivial using a CADisplayLink. It would still be nice to have the functionality built-in without needing to hijack the run loop but this works fine. Example below:

class AnimationProgressObserver {

    typealias ProgressChangeBlock = (_ progress: CGFloat)->()

    private weak var animationView: LOTAnimationView?
    private var onChange: ProgressChangeBlock
    private var lastAnimationProgress: CGFloat = -1

    init(animationView: LOTAnimationView, onChange: @escaping ProgressChangeBlock) {
        self.animationView = animationView
        self.onChange = onChange
        let displayLink: CADisplayLink = CADisplayLink(target: self, selector: #selector(displayLinkTick))
        displayLink.add(to: RunLoop.current, forMode: .commonModes)
    }

    @objc private func displayLinkTick() {
        guard let currentProgress = animationView?.animationProgress else {
            return
        }
        if lastAnimationProgress != currentProgress {
            lastAnimationProgress = currentProgress
            onChange(currentProgress)
        }
    }

}

Usage:

let animationView = LOTAnimationView(name: "...")
let progressObserver = AnimationProgressObserver(animationView: animationView, onChange: { (progress: CGFloat) in
    print("The animation is now at \(progress) progress")
})

All 2 comments

After further investigation it appears this is pretty trivial using a CADisplayLink. It would still be nice to have the functionality built-in without needing to hijack the run loop but this works fine. Example below:

class AnimationProgressObserver {

    typealias ProgressChangeBlock = (_ progress: CGFloat)->()

    private weak var animationView: LOTAnimationView?
    private var onChange: ProgressChangeBlock
    private var lastAnimationProgress: CGFloat = -1

    init(animationView: LOTAnimationView, onChange: @escaping ProgressChangeBlock) {
        self.animationView = animationView
        self.onChange = onChange
        let displayLink: CADisplayLink = CADisplayLink(target: self, selector: #selector(displayLinkTick))
        displayLink.add(to: RunLoop.current, forMode: .commonModes)
    }

    @objc private func displayLinkTick() {
        guard let currentProgress = animationView?.animationProgress else {
            return
        }
        if lastAnimationProgress != currentProgress {
            lastAnimationProgress = currentProgress
            onChange(currentProgress)
        }
    }

}

Usage:

let animationView = LOTAnimationView(name: "...")
let progressObserver = AnimationProgressObserver(animationView: animationView, onChange: { (progress: CGFloat) in
    print("The animation is now at \(progress) progress")
})

Now available in Lottie 3.0 use realtimeAimationFrame

Lottie has been completely rewritten in Swift as of 3.0 (https://github.com/airbnb/lottie-ios/pull/777)

I am closing all issues prior to this release to reduce the noise. If you continue to run into this issues or any issue with Lottie 3.0 please open a new ticket

For continued support of Lottie Objective-c please point to this branch: https://github.com/airbnb/lottie-ios/tree/lottie/objectiveC

Was this page helpful?
0 / 5 - 0 ratings