Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add animationDidFinish API to LottieView #2134

Merged
merged 2 commits into from
Aug 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Example/Example/AnimationPreviewView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ struct AnimationPreviewView: View {
.resizable()
.reloadAnimationTrigger(currentURLIndex, showPlaceholder: false)
.playbackMode(playbackMode)
.animationDidFinish { completed in
if completed {
animationPlaying = false
}
}
.getRealtimeAnimationProgress(animationPlaying ? $sliderValue : nil)

Spacer()
Expand Down
6 changes: 4 additions & 2 deletions Sources/Private/Utility/Helpers/AnimationContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import CoreGraphics
import Foundation
import QuartzCore

/// A completion block for animations. `true` is passed in if the animation completed playing.
public typealias LottieCompletionBlock = (Bool) -> Void
/// A completion block for animations.
/// - `true` is passed in if the animation completed playing.
/// - `false` is passed in if the animation was interrupted and did not complete playing.
public typealias LottieCompletionBlock = (_ completed: Bool) -> Void

// MARK: - AnimationContext

Expand Down
59 changes: 47 additions & 12 deletions Sources/Public/Animation/LottieAnimationLayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,11 @@ public class LottieAnimationLayer: CALayer {
/// marker sequence is playing, the marker sequence will be cancelled.
///
/// - Parameter markers: The list of markers to play sequentially.
open func play(markers: [String]) {
/// - Parameter completion: An optional completion closure to be called when the animation stops.
open func play(
markers: [String],
completion: LottieCompletionBlock? = nil)
{
guard !markers.isEmpty else { return }

defer {
Expand All @@ -319,17 +323,25 @@ public class LottieAnimationLayer: CALayer {
let followingMarkers = Array(markers.dropFirst())

guard animation?.markerMap?[markerToPlay] != nil else {
play(markers: followingMarkers)
play(markers: followingMarkers, completion: completion)
return
}

play(marker: markerToPlay, loopMode: .playOnce, completion: { [weak self] success in
// If the completion handler is called with `success: false` (which typically means
play(marker: markerToPlay, loopMode: .playOnce, completion: { [weak self] completed in
// If the completion handler is called with `completed: false` (which typically means
// that another animation was played by calling some `play` method),
// we should cancel the marker sequence and not play the next marker.
guard success, let self = self else { return }
guard completed, let self = self else {
completion?(false)
return
}

self.play(markers: followingMarkers)
if followingMarkers.isEmpty {
// If we don't have any more markers to play, then the marker sequence has completed.
completion?(completed)
} else {
self.play(markers: followingMarkers, completion: completion)
}
})
}

Expand All @@ -349,7 +361,14 @@ public class LottieAnimationLayer: CALayer {
}

/// Applies the given `LottiePlaybackMode` to this layer.
open func play(_ playbackMode: LottiePlaybackMode) {
/// - Parameter animationCompletionHandler: A closure that is called after
/// an animation triggered by this method completes. This completion
/// handler is **not called** after setting the playback mode to a
/// mode that doesn't animate (e.g. `progress`, `frame`, `time`, or `pause`).
open func play(
_ playbackMode: LottiePlaybackMode,
animationCompletionHandler: LottieCompletionBlock? = nil)
{
switch playbackMode {
case .progress(let progress):
currentProgress = progress
Expand All @@ -364,19 +383,35 @@ public class LottieAnimationLayer: CALayer {
pause()

case .fromProgress(let fromProgress, let toProgress, let loopMode):
play(fromProgress: fromProgress, toProgress: toProgress, loopMode: loopMode, completion: nil)
play(
fromProgress: fromProgress,
toProgress: toProgress,
loopMode: loopMode,
completion: animationCompletionHandler)

case .fromFrame(let fromFrame, let toFrame, let loopMode):
play(fromFrame: fromFrame, toFrame: toFrame, loopMode: loopMode)
play(
fromFrame: fromFrame,
toFrame: toFrame,
loopMode: loopMode,
completion: animationCompletionHandler)

case .fromMarker(let fromMarker, let toMarker, let playEndMarkerFrame, let loopMode):
play(fromMarker: fromMarker, toMarker: toMarker, playEndMarkerFrame: playEndMarkerFrame, loopMode: loopMode)
play(
fromMarker: fromMarker,
toMarker: toMarker,
playEndMarkerFrame: playEndMarkerFrame,
loopMode: loopMode,
completion: animationCompletionHandler)

case .marker(let marker, let loopMode):
play(marker: marker, loopMode: loopMode)
play(
marker: marker,
loopMode: loopMode,
completion: animationCompletionHandler)

case .markers(let markers):
play(markers: markers)
play(markers: markers, completion: animationCompletionHandler)
}
}

Expand Down
19 changes: 15 additions & 4 deletions Sources/Public/Animation/LottieAnimationView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -319,8 +319,12 @@ open class LottieAnimationView: LottieAnimationViewBase {
/// marker sequence is playing, the marker sequence will be cancelled.
///
/// - Parameter markers: The list of markers to play sequentially.
open func play(markers: [String]) {
lottieAnimationLayer.play(markers: markers)
/// - Parameter completion: An optional completion closure to be called when the animation stops.
open func play(
markers: [String],
completion: LottieCompletionBlock? = nil)
{
lottieAnimationLayer.play(markers: markers, completion: completion)
}

/// Stops the animation and resets the view to its start frame.
Expand All @@ -338,8 +342,15 @@ open class LottieAnimationView: LottieAnimationViewBase {
}

/// Applies the given `LottiePlaybackMode` to this layer.
open func play(_ playbackMode: LottiePlaybackMode) {
lottieAnimationLayer.play(playbackMode)
/// - Parameter animationCompletionHandler: A closure that is called after
/// an animation triggered by this method completes. This completion
/// handler is **not called** after setting the playback mode to a
/// mode that doesn't animate (e.g. `progress`, `frame`, `time`, or `pause`).
open func play(
_ playbackMode: LottiePlaybackMode,
animationCompletionHandler: LottieCompletionBlock? = nil)
{
lottieAnimationLayer.play(playbackMode, animationCompletionHandler: animationCompletionHandler)
}

// MARK: Public
Expand Down
14 changes: 13 additions & 1 deletion Sources/Public/Animation/LottieView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ public struct LottieView<Placeholder: View>: UIViewConfiguringSwiftUIView {
let playbackMode = playbackMode,
playbackMode != context.view.currentPlaybackMode
{
context.view.play(playbackMode)
context.view.play(playbackMode, animationCompletionHandler: animationCompletionHandler)
}
}
.configurations(configurations)
Expand Down Expand Up @@ -189,6 +189,17 @@ public struct LottieView<Placeholder: View>: UIViewConfiguringSwiftUIView {
return copy
}

/// Returns a copy of this view with the given `LottieCompletionBlock` that is called
/// when an animation finishes playing.
public func animationDidFinish(_ animationCompletionHandler: LottieCompletionBlock?) -> Self {
var copy = self
copy.animationCompletionHandler = { completed in
animationCompletionHandler?(completed)
copy.animationCompletionHandler?(completed)
}
return copy
}

/// Returns a copy of this view updated to have the provided background behavior.
public func backgroundBehavior(_ value: LottieBackgroundBehavior) -> Self {
configure { view in
Expand Down Expand Up @@ -394,6 +405,7 @@ public struct LottieView<Placeholder: View>: UIViewConfiguringSwiftUIView {
private var playbackMode: LottiePlaybackMode?
private var reloadAnimationTrigger: AnyEquatable?
private var loadAnimation: (() async throws -> LottieAnimationSource?)?
private var animationCompletionHandler: LottieCompletionBlock?
private var showPlaceholderWhileReloading = false
private var imageProvider: AnimationImageProvider?
private var textProvider: AnimationTextProvider = DefaultTextProvider()
Expand Down
Loading