Skip to content

Commit

Permalink
Add API for playing multiple markers sequentially (airbnb#2084)
Browse files Browse the repository at this point in the history
  • Loading branch information
calda authored and Igor Moroz committed May 22, 2024
1 parent d00aada commit 828052c
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 1 deletion.
38 changes: 38 additions & 0 deletions Example/iOS/ViewControllers/AnimationPreviewViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,12 @@ class AnimationPreviewViewController: UIViewController {
updateAnimation()
}),
]),

UIAction(
title: "Play Markers...",
handler: { [unowned self] _ in
displayMarkerList()
}),
]))
}

Expand All @@ -248,4 +254,36 @@ class AnimationPreviewViewController: UIViewController {
animationView.animationSpeed = speed
configureSettingsMenu()
}

private func displayMarkerList() {
let markersList: String
let markerNames = animationView.animation?.markerNames ?? []
if markerNames.isEmpty {
markersList = "No markers included in animation"
} else {
markersList = markerNames.joined(separator: ", ")
}

let alert = UIAlertController(title: "Markers", message: markersList, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))

alert.addTextField { textField in
textField.placeholder = "Comma separated list of markers to play in order"
}

alert.addAction(UIAlertAction(title: "Play", style: .default) { [weak alert, weak self] _ in
guard
let self = self,
let textInput = alert?.textFields?.first?.text,
!textInput.isEmpty
else { return }

let markersToPlay = textInput.components(separatedBy: ",")
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }

self.animationView.play(markers: markersToPlay)
})
present(alert, animated: true)
}

}
36 changes: 36 additions & 0 deletions Sources/Public/Animation/LottieAnimationLayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,42 @@ public class LottieAnimationLayer: CALayer {
completion: completion)
}

/// Plays the given markers sequentially in order.
///
/// A marker is a point in time with an associated duration that is encoded into the
/// animation data and assigned a name. Multiple markers can be played sequentially
/// to create programmable animations.
///
/// If a marker is not found, it will be skipped.
///
/// If a marker doesn't have a duration value, it will play with a duration of 0
/// (effectively being skipped).
///
/// If another animation is played (by calling any `play` method) while this
/// marker sequence is playing, the marker sequence will be cancelled.
///
/// - Parameter markers: The list of markers to play sequentially.
open func play(markers: [String]) {
guard !markers.isEmpty else { return }

let markerToPlay = markers[0]
let followingMarkers = Array(markers.dropFirst())

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

play(marker: markerToPlay, loopMode: .playOnce, completion: { [weak self] success in
// If the completion handler is called with `success: 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 }

self.play(markers: followingMarkers)
})
}

/// Stops the animation and resets the layer to its start frame.
///
/// The completion closure will be called with `false`
Expand Down
19 changes: 19 additions & 0 deletions Sources/Public/Animation/LottieAnimationView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,25 @@ open class LottieAnimationView: LottieAnimationViewBase {
lottieAnimationLayer.play(marker: marker, loopMode: loopMode, completion: completion)
}

/// Plays the given markers sequentially in order.
///
/// A marker is a point in time with an associated duration that is encoded into the
/// animation data and assigned a name. Multiple markers can be played sequentially
/// to create programmable animations.
///
/// If a marker is not found, it will be skipped.
///
/// If a marker doesn't have a duration value, it will play with a duration of 0
/// (effectively being skipped).
///
/// If another animation is played (by calling any `play` method) while this
/// 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)
}

/// Stops the animation and resets the view to its start frame.
///
/// The completion closure will be called with `false`
Expand Down
2 changes: 1 addition & 1 deletion Tests/Samples/Issues/issue_1915.json

Large diffs are not rendered by default.

0 comments on commit 828052c

Please sign in to comment.