Comprehensive playback modes and control systems for fine-grained animation management including loop modes, playback states, and marker-based navigation.
Main playback mode configuration system providing declarative control over animation playback behavior.
/**
* Configuration for animation playback behavior
* Supports both paused states and playing modes
*/
public enum LottiePlaybackMode {
case paused(at: PausedState)
case playing(_ mode: PlaybackMode)
}
/**
* Specification for paused animation state
*/
public enum PausedState {
/** Pause at current frame position */
case currentFrame
/** Pause at specific progress value */
case progress(AnimationProgressTime)
/** Pause at specific frame number */
case frame(AnimationFrameTime)
/** Pause at specific time in seconds */
case time(TimeInterval)
/** Pause at marker with optional position */
case marker(String, position: MarkerPosition = .start)
}
/**
* Marker position within marker duration
*/
public enum MarkerPosition {
case start
case end
}
/**
* Specification for active playback behavior
*/
public enum PlaybackMode {
/** Play between progress values with loop mode */
case fromProgress(
AnimationProgressTime,
toProgress: AnimationProgressTime,
loopMode: LottieLoopMode
)
/** Play between frame numbers with loop mode */
case fromFrame(
AnimationFrameTime,
toFrame: AnimationFrameTime,
loopMode: LottieLoopMode
)
/** Play between markers with options */
case fromMarker(
String,
toMarker: String,
playEndMarkerFrame: Bool = true,
loopMode: LottieLoopMode
)
/** Play single marker with loop mode */
case marker(String, loopMode: LottieLoopMode)
/** Play sequence of markers */
case markers([String])
}Usage Examples:
import Lottie
class PlaybackController {
let animationView = LottieAnimationView()
func configurePlayback() {
// Pause at specific states
animationView.setPlaybackMode(.paused(at: .progress(0.5)))
animationView.setPlaybackMode(.paused(at: .marker("checkpoint")))
animationView.setPlaybackMode(.paused(at: .frame(30)))
// Play with different modes
animationView.setPlaybackMode(.playing(.fromProgress(0.2, toProgress: 0.8, loopMode: .loop)))
animationView.setPlaybackMode(.playing(.marker("intro", loopMode: .playOnce)))
animationView.setPlaybackMode(.playing(.fromMarker("start", toMarker: "end", loopMode: .autoReverse)))
animationView.setPlaybackMode(.playing(.markers(["intro", "main", "outro"])))
}
}Animation loop behavior configuration supporting various looping patterns and repetition counts.
/**
* Animation loop behavior options
*/
public enum LottieLoopMode {
/** Play animation once from beginning to end then stop */
case playOnce
/** Loop animation continuously from beginning to end */
case loop
/** Play forward to end, then backward to beginning, repeat */
case autoReverse
/** Loop specified number of times (fractional values supported) */
case `repeat`(Float)
/** Play forward/backward specified number of times */
case repeatBackwards(Float)
}Usage Examples:
import Lottie
class LoopingExamples {
let animationView = LottieAnimationView()
func demonstrateLoopModes() {
// Basic loop modes
animationView.loopMode = .playOnce
animationView.loopMode = .loop
animationView.loopMode = .autoReverse
// Repeat specific number of times
animationView.loopMode = .repeat(2.5) // Play 2.5 times
animationView.loopMode = .repeatBackwards(3) // Forward/backward 3 times
// Use with play methods
animationView.play(
fromProgress: 0,
toProgress: 1,
loopMode: .repeat(5)
) { finished in
print("Repeated 5 times, finished: \(finished)")
}
}
}Behavior configuration for when the application moves to the background, providing different strategies for handling ongoing animations.
/**
* Behavior when application moves to background
*/
public enum LottieBackgroundBehavior {
/** Stop animation and reset to beginning */
case stop
/** Pause animation in current state */
case pause
/** Pause in background, restart when returning to foreground */
case pauseAndRestore
/** Stop animation and jump to end state */
case forceFinish
/** Continue playing animation in background */
case continuePlaying
}Usage Examples:
import Lottie
class BackgroundHandling {
let animationView = LottieAnimationView()
func configureBackgroundBehavior() {
// For loading animations that should stop when backgrounded
animationView.backgroundBehavior = .stop
// For progress indicators that should pause and resume
animationView.backgroundBehavior = .pauseAndRestore
// For animations that must complete (e.g., form submission feedback)
animationView.backgroundBehavior = .forceFinish
// For ambient animations (use carefully for battery life)
animationView.backgroundBehavior = .continuePlaying
}
}Helper methods for converting between different time representations in animations.
/**
* Animation time conversion methods available on LottieAnimation
*/
extension LottieAnimation {
/**
* Get progress time for named marker
* @param marker - Marker name to look up
* @returns Progress time (0.0-1.0) for marker start, nil if not found
*/
public func progressTime(forMarker marker: String) -> AnimationProgressTime?
/**
* Get frame time for named marker
* @param marker - Marker name to look up
* @returns Frame number for marker start, nil if not found
*/
public func frameTime(forMarker marker: String) -> AnimationFrameTime?
/**
* Get duration frame time for named marker
* @param marker - Marker name to look up
* @returns Frame duration of marker, nil if not found
*/
public func durationFrameTime(forMarker marker: String) -> AnimationFrameTime?
/**
* Convert frame number to progress value
* @param frame - Frame number to convert
* @param clamped - Whether to clamp result to 0.0-1.0 range
* @returns Progress value (0.0-1.0)
*/
public func progressTime(forFrame frame: AnimationFrameTime, clamped: Bool = true) -> AnimationProgressTime
/**
* Convert progress value to frame number
* @param progress - Progress value (0.0-1.0) to convert
* @returns Corresponding frame number
*/
public func frameTime(forProgress progress: AnimationProgressTime) -> AnimationFrameTime
/**
* Convert frame number to time in seconds
* @param frame - Frame number to convert
* @returns Time in seconds
*/
public func time(forFrame frame: AnimationFrameTime) -> TimeInterval
/**
* Convert time in seconds to frame number
* @param time - Time in seconds to convert
* @returns Corresponding frame number
*/
public func frameTime(forTime time: TimeInterval) -> AnimationFrameTime
}Usage Examples:
import Lottie
class TimeConversion {
let animation = LottieAnimation.named("timeline")!
func demonstrateConversions() {
// Work with markers
if let introProgress = animation.progressTime(forMarker: "intro") {
print("Intro starts at progress: \(introProgress)")
}
if let outroFrame = animation.frameTime(forMarker: "outro") {
print("Outro starts at frame: \(outroFrame)")
}
// Convert between time formats
let midFrame = animation.frameTime(forProgress: 0.5)
let midTime = animation.time(forFrame: midFrame)
let backToProgress = animation.progressTime(forFrame: midFrame)
print("Mid-point: progress=0.5, frame=\(midFrame), time=\(midTime)s")
// Use conversions for precise playback
let startFrame = animation.frameTime(forMarker: "highlight") ?? 0
let endFrame = startFrame + 60 // Play for 60 frames
let startProgress = animation.progressTime(forFrame: startFrame)
let endProgress = animation.progressTime(forFrame: endFrame)
// Play converted segment
animationView.play(
fromProgress: startProgress,
toProgress: endProgress,
loopMode: .playOnce
)
}
}Properties and methods for monitoring current playback state and real-time animation values.
/**
* Playback monitoring properties and methods
*/
extension LottieAnimationView {
// MARK: - State Properties
/** Whether animation is currently playing */
public var isAnimationPlaying: Bool { get }
/** Whether animation will play when added to window hierarchy */
public var isAnimationQueued: Bool { get }
/** Current progress from 0.0 to 1.0 */
public var currentProgress: AnimationProgressTime { get set }
/** Current time in seconds */
public var currentTime: TimeInterval { get set }
/** Current frame number */
public var currentFrame: AnimationFrameTime { get set }
/** Real-time frame while animation is playing (updates during playback) */
public var realtimeAnimationFrame: AnimationFrameTime { get }
/** Real-time progress while animation is playing (updates during playback) */
public var realtimeAnimationProgress: AnimationProgressTime { get }
/** Current playback mode configuration */
public var currentPlaybackMode: LottiePlaybackMode? { get }
/** Animation speed multiplier (1.0 = normal speed, 2.0 = double speed, etc.) */
public var animationSpeed: CGFloat { get set }
// MARK: - Control Methods
/** Stop animation and reset to beginning */
public func stop()
/** Pause animation at current frame */
public func pause()
/**
* Pause animation at specific state
* @param pausedState - Where to pause the animation
*/
public func pause(at pausedState: PausedState)
}Usage Examples:
import Lottie
class PlaybackMonitoring {
let animationView = LottieAnimationView()
var displayLink: CADisplayLink?
func startMonitoring() {
displayLink = CADisplayLink(target: self, selector: #selector(updatePlaybackInfo))
displayLink?.add(to: .main, forMode: .common)
}
@objc func updatePlaybackInfo() {
guard animationView.isAnimationPlaying else { return }
let currentFrame = animationView.realtimeAnimationFrame
let currentProgress = animationView.realtimeAnimationProgress
print("Playing: frame=\(currentFrame), progress=\(currentProgress)")
// Update UI elements like progress bars, scrubbers, etc.
updateProgressUI(progress: currentProgress)
}
func controlPlayback() {
// Speed control
animationView.animationSpeed = 2.0 // Double speed
animationView.animationSpeed = 0.5 // Half speed
// State control
if animationView.isAnimationPlaying {
animationView.pause()
} else {
animationView.play()
}
// Precise positioning
animationView.pause(at: .progress(0.75))
animationView.pause(at: .marker("checkpoint", position: .end))
}
func updateProgressUI(progress: AnimationProgressTime) {
// Update progress indicator
}
}Complex playback scenarios combining multiple control mechanisms for sophisticated animation choreography.
/**
* Advanced playback coordination methods
*/
extension LottieAnimationView {
/**
* Chain multiple playback sequences
*/
func playSequence(
segments: [(from: AnimationProgressTime, to: AnimationProgressTime, loopMode: LottieLoopMode)],
completion: @escaping LottieCompletionBlock
) {
guard !segments.isEmpty else {
completion(true)
return
}
var remainingSegments = segments
let currentSegment = remainingSegments.removeFirst()
play(
fromProgress: currentSegment.from,
toProgress: currentSegment.to,
loopMode: currentSegment.loopMode
) { [weak self] finished in
guard finished else {
completion(false)
return
}
self?.playSequence(segments: remainingSegments, completion: completion)
}
}
/**
* Coordinate animation with external timing
*/
func synchronizeWithTimer(
duration: TimeInterval,
updateHandler: @escaping (AnimationProgressTime) -> Void,
completion: @escaping LottieCompletionBlock
) {
let startTime = CACurrentMediaTime()
let timer = CADisplayLink(target: self, selector: #selector(timerUpdate))
var timerCompletion: LottieCompletionBlock?
timerCompletion = { finished in
timer.invalidate()
completion(finished)
}
// Store timer state (implementation would need proper storage)
timer.add(to: .main, forMode: .common)
}
}Usage Examples:
import Lottie
class AdvancedPlaybackController {
let animationView = LottieAnimationView()
func demonstrateAdvancedPatterns() {
// Sequential segment playback
let segments = [
(from: 0.0, to: 0.3, loopMode: LottieLoopMode.playOnce),
(from: 0.3, to: 0.7, loopMode: LottieLoopMode.repeat(2)),
(from: 0.7, to: 1.0, loopMode: LottieLoopMode.playOnce)
]
animationView.playSequence(segments: segments) { finished in
print("Complex sequence completed: \(finished)")
}
// Interactive scrubbing
setupInteractiveScrubbing()
// Synchronized multi-animation playback
synchronizeAnimations()
}
func setupInteractiveScrubbing() {
// Pause animation for manual control
animationView.pause()
// Add gesture recognizer for scrubbing
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handleScrub(_:)))
animationView.addGestureRecognizer(panGesture)
}
@objc func handleScrub(_ gesture: UIPanGestureRecognizer) {
let translation = gesture.translation(in: animationView)
let progress = max(0, min(1, animationView.currentProgress + translation.x / animationView.bounds.width))
animationView.currentProgress = progress
gesture.setTranslation(.zero, in: animationView)
}
func synchronizeAnimations() {
let animation1 = LottieAnimationView(name: "sync1")
let animation2 = LottieAnimationView(name: "sync2")
// Start both animations simultaneously
let group = DispatchGroup()
group.enter()
animation1.play { _ in group.leave() }
group.enter()
animation2.play { _ in group.leave() }
group.notify(queue: .main) {
print("All synchronized animations completed")
}
}
}