Skip to content

Commit

Permalink
Add support for multiple animations in dotLottie files (airbnb#2074)
Browse files Browse the repository at this point in the history
  • Loading branch information
eharrison authored and iago849 committed Feb 8, 2024
1 parent 0b03df6 commit fe78cfb
Show file tree
Hide file tree
Showing 20 changed files with 119 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -248,5 +248,4 @@ class AnimationPreviewViewController: UIViewController {
animationView.animationSpeed = speed
configureSettingsMenu()
}

}
29 changes: 21 additions & 8 deletions Lottie.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -635,9 +635,6 @@
6C48784728FF20140005AF07 /* DotLottieManifest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C4877FB28FF20140005AF07 /* DotLottieManifest.swift */; };
6C48784828FF20140005AF07 /* DotLottieManifest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C4877FB28FF20140005AF07 /* DotLottieManifest.swift */; };
6C48784928FF20140005AF07 /* DotLottieManifest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C4877FB28FF20140005AF07 /* DotLottieManifest.swift */; };
6C48784B29008ACF0005AF07 /* DotLottieConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C48784A29008ACF0005AF07 /* DotLottieConfiguration.swift */; };
6C48784C29008ACF0005AF07 /* DotLottieConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C48784A29008ACF0005AF07 /* DotLottieConfiguration.swift */; };
6C48784D29008ACF0005AF07 /* DotLottieConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C48784A29008ACF0005AF07 /* DotLottieConfiguration.swift */; };
6C48785229017CBF0005AF07 /* DotLottieCacheProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C48785129017CBF0005AF07 /* DotLottieCacheProvider.swift */; };
6C48785329017CBF0005AF07 /* DotLottieCacheProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C48785129017CBF0005AF07 /* DotLottieCacheProvider.swift */; };
6C48785429017CBF0005AF07 /* DotLottieCacheProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C48785129017CBF0005AF07 /* DotLottieCacheProvider.swift */; };
Expand All @@ -649,6 +646,9 @@
6C4878602901D8C70005AF07 /* DotLottieImageProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C48785F2901D8C70005AF07 /* DotLottieImageProvider.swift */; };
6C4878612901D8C70005AF07 /* DotLottieImageProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C48785F2901D8C70005AF07 /* DotLottieImageProvider.swift */; };
6C4878622901D8C70005AF07 /* DotLottieImageProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C48785F2901D8C70005AF07 /* DotLottieImageProvider.swift */; };
6C7698432A38A71200E9BEF4 /* DotLottieConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C7698422A38A71200E9BEF4 /* DotLottieConfiguration.swift */; };
6C7698442A38A71200E9BEF4 /* DotLottieConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C7698422A38A71200E9BEF4 /* DotLottieConfiguration.swift */; };
6C7698452A38A71200E9BEF4 /* DotLottieConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C7698422A38A71200E9BEF4 /* DotLottieConfiguration.swift */; };
6CC544932902FF7D00212722 /* DotLottieCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C48785529017D1D0005AF07 /* DotLottieCache.swift */; };
6D0E635F28246BD0007C5DB6 /* Difference in Frameworks */ = {isa = PBXBuildFile; productRef = 6D0E635E28246BD0007C5DB6 /* Difference */; };
6D99D6432823790700E5205B /* LegacyGradientFillRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D99D6422823790700E5205B /* LegacyGradientFillRenderer.swift */; };
Expand Down Expand Up @@ -916,11 +916,12 @@
6C4877E328FF20140005AF07 /* DotLottieFile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DotLottieFile.swift; sourceTree = "<group>"; };
6C4877E428FF20140005AF07 /* DotLottieUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DotLottieUtils.swift; sourceTree = "<group>"; };
6C4877FB28FF20140005AF07 /* DotLottieManifest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DotLottieManifest.swift; sourceTree = "<group>"; };
6C48784A29008ACF0005AF07 /* DotLottieConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DotLottieConfiguration.swift; sourceTree = "<group>"; };
6C48785129017CBF0005AF07 /* DotLottieCacheProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DotLottieCacheProvider.swift; sourceTree = "<group>"; };
6C48785529017D1D0005AF07 /* DotLottieCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DotLottieCache.swift; sourceTree = "<group>"; };
6C4878592901811D0005AF07 /* DotLottieFileHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DotLottieFileHelpers.swift; sourceTree = "<group>"; };
6C48785F2901D8C70005AF07 /* DotLottieImageProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DotLottieImageProvider.swift; sourceTree = "<group>"; };
6C49605B2A33452900BDF3CB /* DotLottieAnimationMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DotLottieAnimationMode.swift; sourceTree = "<group>"; };
6C7698422A38A71200E9BEF4 /* DotLottieConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DotLottieConfiguration.swift; sourceTree = "<group>"; };
6D99D6422823790700E5205B /* LegacyGradientFillRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyGradientFillRenderer.swift; sourceTree = "<group>"; };
6DB3BDB528243FA5002A276D /* ValueProvidersTests.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = ValueProvidersTests.swift; sourceTree = "<group>"; tabWidth = 2; };
6DB3BDB7282454A6002A276D /* DictionaryInitializable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DictionaryInitializable.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -977,6 +978,7 @@
2EAF59C027A0798600E00531 /* Sources */,
2E8040BA27A07343006E74CB /* Tests */,
2E80409B27A0725D006E74CB /* Products */,
6C7698412A38A6B800E9BEF4 /* Recovered References */,
);
sourceTree = "<group>";
};
Expand Down Expand Up @@ -1645,6 +1647,7 @@
children = (
6C4877E328FF20140005AF07 /* DotLottieFile.swift */,
6C4878592901811D0005AF07 /* DotLottieFileHelpers.swift */,
6C7698422A38A71200E9BEF4 /* DotLottieConfiguration.swift */,
6C48785D2901A4110005AF07 /* Cache */,
);
path = DotLottie;
Expand All @@ -1665,13 +1668,20 @@
6C4877FB28FF20140005AF07 /* DotLottieManifest.swift */,
6C4877E428FF20140005AF07 /* DotLottieUtils.swift */,
6C4877E228FF20140005AF07 /* DotLottieAnimation.swift */,
6C48784A29008ACF0005AF07 /* DotLottieConfiguration.swift */,
6C48785F2901D8C70005AF07 /* DotLottieImageProvider.swift */,
6CFA1077290B12B900873A98 /* ZipFoundation */,
);
path = DotLottie;
sourceTree = "<group>";
};
6C7698412A38A6B800E9BEF4 /* Recovered References */ = {
isa = PBXGroup;
children = (
6C49605B2A33452900BDF3CB /* DotLottieAnimationMode.swift */,
);
name = "Recovered References";
sourceTree = "<group>";
};
6CFA1077290B12B900873A98 /* ZipFoundation */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -2021,6 +2031,7 @@
2EAF5AD727A0798700E00531 /* Vectors.swift in Sources */,
2E9C95E22822F43100677516 /* Group.swift in Sources */,
2E9C97112822F43100677516 /* Keyframes+combined.swift in Sources */,
6C49605C2A33452900BDF3CB /* DotLottieAnimationMode.swift in Sources */,
0887347B28F0CCDD00458627 /* LottieAnimationView.swift in Sources */,
2EAF5AD127A0798700E00531 /* AnimatedControl.swift in Sources */,
2E9C966F2822F43100677516 /* LayerTextProvider.swift in Sources */,
Expand All @@ -2034,7 +2045,6 @@
6C48780528FF20140005AF07 /* DotLottieUtils.swift in Sources */,
2E9C96B42822F43100677516 /* AnyNodeProperty.swift in Sources */,
2EAF5AF827A0798700E00531 /* FloatValueProvider.swift in Sources */,
6C48784B29008ACF0005AF07 /* DotLottieConfiguration.swift in Sources */,
2E9C968D2822F43100677516 /* PassThroughOutputNode.swift in Sources */,
087584CF29B2BC8200BC168F /* Data+Compression.swift in Sources */,
2EAF5AB627A0798700E00531 /* CompatibleAnimationKeypath.swift in Sources */,
Expand Down Expand Up @@ -2067,6 +2077,7 @@
2EAF5AFE27A0798700E00531 /* GradientValueProvider.swift in Sources */,
2E9C96BD2822F43100677516 /* AnyValueContainer.swift in Sources */,
2E9C96602822F43100677516 /* LayerFontProvider.swift in Sources */,
6C7698432A38A71200E9BEF4 /* DotLottieConfiguration.swift in Sources */,
2E9C96242822F43100677516 /* KeyframeGroup.swift in Sources */,
2E9C96FF2822F43100677516 /* BaseAnimationLayer.swift in Sources */,
2E9C96AB2822F43100677516 /* GradientStrokeNode.swift in Sources */,
Expand Down Expand Up @@ -2269,6 +2280,7 @@
2EAF5AD827A0798700E00531 /* Vectors.swift in Sources */,
2E9C95E32822F43100677516 /* Group.swift in Sources */,
2E9C97122822F43100677516 /* Keyframes+combined.swift in Sources */,
6C49605D2A33452900BDF3CB /* DotLottieAnimationMode.swift in Sources */,
0887347C28F0CCDD00458627 /* LottieAnimationView.swift in Sources */,
2EAF5AD227A0798700E00531 /* AnimatedControl.swift in Sources */,
2E9C96702822F43100677516 /* LayerTextProvider.swift in Sources */,
Expand All @@ -2282,7 +2294,6 @@
6C48780628FF20140005AF07 /* DotLottieUtils.swift in Sources */,
2E9C96B52822F43100677516 /* AnyNodeProperty.swift in Sources */,
2EAF5AF927A0798700E00531 /* FloatValueProvider.swift in Sources */,
6C48784C29008ACF0005AF07 /* DotLottieConfiguration.swift in Sources */,
2E9C968E2822F43100677516 /* PassThroughOutputNode.swift in Sources */,
087584D029B2BC8200BC168F /* Data+Compression.swift in Sources */,
2EAF5AB727A0798700E00531 /* CompatibleAnimationKeypath.swift in Sources */,
Expand Down Expand Up @@ -2315,6 +2326,7 @@
2EAF5AFF27A0798700E00531 /* GradientValueProvider.swift in Sources */,
2E9C96BE2822F43100677516 /* AnyValueContainer.swift in Sources */,
2E9C96612822F43100677516 /* LayerFontProvider.swift in Sources */,
6C7698442A38A71200E9BEF4 /* DotLottieConfiguration.swift in Sources */,
2E9C96252822F43100677516 /* KeyframeGroup.swift in Sources */,
2E9C97002822F43100677516 /* BaseAnimationLayer.swift in Sources */,
2E9C96AC2822F43100677516 /* GradientStrokeNode.swift in Sources */,
Expand Down Expand Up @@ -2493,6 +2505,7 @@
2EAF5AD927A0798700E00531 /* Vectors.swift in Sources */,
2E9C95E42822F43100677516 /* Group.swift in Sources */,
2E9C97132822F43100677516 /* Keyframes+combined.swift in Sources */,
6C49605E2A33452900BDF3CB /* DotLottieAnimationMode.swift in Sources */,
0887347D28F0CCDD00458627 /* LottieAnimationView.swift in Sources */,
2EAF5AD327A0798700E00531 /* AnimatedControl.swift in Sources */,
2E9C96712822F43100677516 /* LayerTextProvider.swift in Sources */,
Expand All @@ -2506,7 +2519,6 @@
6C48780728FF20140005AF07 /* DotLottieUtils.swift in Sources */,
2E9C96B62822F43100677516 /* AnyNodeProperty.swift in Sources */,
2EAF5AFA27A0798700E00531 /* FloatValueProvider.swift in Sources */,
6C48784D29008ACF0005AF07 /* DotLottieConfiguration.swift in Sources */,
2E9C968F2822F43100677516 /* PassThroughOutputNode.swift in Sources */,
087584D129B2BC8200BC168F /* Data+Compression.swift in Sources */,
2EAF5AB827A0798700E00531 /* CompatibleAnimationKeypath.swift in Sources */,
Expand Down Expand Up @@ -2539,6 +2551,7 @@
2EAF5B0027A0798700E00531 /* GradientValueProvider.swift in Sources */,
2E9C96BF2822F43100677516 /* AnyValueContainer.swift in Sources */,
2E9C96622822F43100677516 /* LayerFontProvider.swift in Sources */,
6C7698452A38A71200E9BEF4 /* DotLottieConfiguration.swift in Sources */,
2E9C96262822F43100677516 /* KeyframeGroup.swift in Sources */,
2E9C97012822F43100677516 /* BaseAnimationLayer.swift in Sources */,
2E9C96AD2822F43100677516 /* GradientStrokeNode.swift in Sources */,
Expand Down
18 changes: 16 additions & 2 deletions Sources/Private/Model/DotLottie/DotLottieAnimation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

import Foundation

// MARK: - DotLottieAnimation

struct DotLottieAnimation: Codable {
/// Id of Animation
var id: String
Expand All @@ -21,11 +23,16 @@ struct DotLottieAnimation: Codable {
var direction: Int? = 1

/// mode - "bounce" | "normal"
var mode: String? = "normal"
var mode: DotLottieAnimationMode? = .normal

/// Loop mode for animation
var loopMode: LottieLoopMode {
mode == "bounce" ? .autoReverse : ((loop ?? false) ? .loop : .playOnce)
switch mode {
case .bounce:
return .autoReverse
case .normal, nil:
return ((loop ?? false) ? .loop : .playOnce)
}
}

/// Animation speed
Expand All @@ -41,3 +48,10 @@ struct DotLottieAnimation: Codable {
return try LottieAnimation.from(data: data)
}
}

// MARK: - DotLottieAnimationMode

enum DotLottieAnimationMode: String, Codable {
case normal
case bounce
}
15 changes: 0 additions & 15 deletions Sources/Private/Model/DotLottie/DotLottieConfiguration.swift

This file was deleted.

36 changes: 28 additions & 8 deletions Sources/Public/Animation/LottieAnimationLayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -549,15 +549,24 @@ public class LottieAnimationLayer: CALayer {
from dotLottieFile: DotLottieFile)
{
guard let dotLottieAnimation = dotLottieFile.animation(for: animationId) else { return }
loadAnimation(dotLottieAnimation)
}

loopMode = dotLottieAnimation.configuration.loopMode
animationSpeed = CGFloat(dotLottieAnimation.configuration.speed)

if let imageProvider = dotLottieAnimation.configuration.imageProvider {
self.imageProvider = imageProvider
}

animation = dotLottieAnimation.animation
/// Sets the lottie file backing the animation layer. Setting this will clear the
/// layer's contents, completion blocks and current state. The new animation will
/// be loaded up and set to the beginning of its timeline.
/// The loopMode, animationSpeed and imageProvider will be set according
/// to lottie file settings
/// - Parameters:
/// - atIndex: Internal animation index to play.
/// Defaults to play first animation in file.
/// - dotLottieFile: Lottie file to play
public func loadAnimation(
atIndex index: Int,
from dotLottieFile: DotLottieFile)
{
guard let dotLottieAnimation = dotLottieFile.animation(at: index) else { return }
loadAnimation(dotLottieAnimation)
}

/// Reloads the images supplied to the animation from the `imageProvider`
Expand Down Expand Up @@ -1186,6 +1195,17 @@ public class LottieAnimationLayer: CALayer {
/// The `LottieBackgroundBehavior` that was specified manually by setting `self.backgroundBehavior`
private var _backgroundBehavior: LottieBackgroundBehavior?

private func loadAnimation(_ dotLottieAnimation: DotLottieFile.Animation) {
loopMode = dotLottieAnimation.configuration.loopMode
animationSpeed = CGFloat(dotLottieAnimation.configuration.speed)

if let imageProvider = dotLottieAnimation.configuration.imageProvider {
self.imageProvider = imageProvider
}

animation = dotLottieAnimation.animation
}

}

// MARK: - LottieLoopMode + caAnimationConfiguration
Expand Down
16 changes: 16 additions & 0 deletions Sources/Public/Animation/LottieAnimationView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,22 @@ open class LottieAnimationView: LottieAnimationViewBase {
lottieAnimationLayer.loadAnimation(animationId, from: dotLottieFile)
}

/// Sets the lottie file backing the animation view. Setting this will clear the
/// view's contents, completion blocks and current state. The new animation will
/// be loaded up and set to the beginning of its timeline.
/// The loopMode, animationSpeed and imageProvider will be set according
/// to lottie file settings
/// - Parameters:
/// - atIndex: Internal animation index to play. Optional
/// Defaults to play first animation in file.
/// - dotLottieFile: Lottie file to play
public func loadAnimation(
atIndex index: Int,
from dotLottieFile: DotLottieFile)
{
lottieAnimationLayer.loadAnimation(atIndex: index, from: dotLottieFile)
}

/// Reloads the images supplied to the animation from the `imageProvider`
public func reloadImages() {
lottieAnimationLayer.reloadImages()
Expand Down
24 changes: 24 additions & 0 deletions Sources/Public/DotLottie/DotLottieConfiguration.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// DotLottieConfiguration.swift
// Lottie
//
// Created by Evandro Hoffmann on 19/10/22.
//

// MARK: - DotLottieConfiguration

/// The `DotLottieConfiguration` model holds the presets extracted from DotLottieAnimation
/// The presets are used as input to setup `LottieAnimationView` before playing the animation.
public struct DotLottieConfiguration {
/// id of the animation
public var id: String

/// Animation Image Provider
public var imageProvider: AnimationImageProvider?

/// Loop behaviour of animation
public var loopMode: LottieLoopMode

/// Playback speed of animation
public var speed: Double
}
18 changes: 13 additions & 5 deletions Sources/Public/DotLottie/DotLottieFile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,18 @@ public final class DotLottieFile {
try decompress(data: data, to: fileUrl)
}

// MARK: Internal
// MARK: Public

/// Definition for a single animation within a `DotLottieFile`
struct Animation {
let animation: LottieAnimation
let configuration: DotLottieConfiguration
public struct Animation {
public let animation: LottieAnimation
public let configuration: DotLottieConfiguration
}

/// List of `LottieAnimation` in the file
private(set) var animations: [Animation] = []
public private(set) var animations: [Animation] = []

// MARK: Internal

/// Image provider for animations
private(set) var imageProvider: AnimationImageProvider?
Expand All @@ -60,6 +62,12 @@ public final class DotLottieFile {
}
}

/// The `LottieAnimation` and `DotLottieConfiguration` for the given animation index in this file
func animation(at index: Int) -> DotLottieFile.Animation? {
guard index < animations.count else { return nil }
return animations[index]
}

// MARK: Private

private static let manifestFileName = "manifest.json"
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Supports Core Animation engine
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit fe78cfb

Please sign in to comment.