lottie-ios 4.2.0 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/main.yml +117 -11
- package/Gemfile +1 -0
- package/Gemfile.lock +5 -0
- package/Lottie.xcodeproj/project.pbxproj +1542 -194
- package/Lottie.xcodeproj/project.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/Lottie.xcodeproj/xcshareddata/xcschemes/Lottie (iOS).xcscheme +1 -1
- package/Lottie.xcodeproj/xcshareddata/xcschemes/Lottie (macOS).xcscheme +1 -1
- package/Lottie.xcodeproj/xcshareddata/xcschemes/Lottie (tvOS).xcscheme +4 -5
- package/Lottie.xcodeproj/xcshareddata/xcschemes/Lottie (visionOS).xcscheme +66 -0
- package/Lottie.xcodeproj/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +18 -0
- package/Lottie.xcworkspace/xcshareddata/swiftpm/Package.resolved +2 -11
- package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +346 -102
- package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Expressions.xcexplist +16 -5
- package/Package.resolved +2 -2
- package/Package.swift +16 -9
- package/README.md +2 -2
- package/Rakefile +122 -25
- package/Sources/Private/CoreAnimation/Animations/DropShadowAnimation.swift +160 -0
- package/Sources/Private/CoreAnimation/Animations/LayerProperty.swift +83 -10
- package/Sources/Private/CoreAnimation/Animations/TransformAnimations.swift +85 -79
- package/Sources/Private/CoreAnimation/CoreAnimationLayer.swift +7 -7
- package/Sources/Private/CoreAnimation/Extensions/Keyframes+combined.swift +67 -6
- package/Sources/Private/CoreAnimation/Layers/AnimationLayer.swift +2 -2
- package/Sources/Private/CoreAnimation/Layers/BaseCompositionLayer.swift +9 -0
- package/Sources/Private/CoreAnimation/Layers/ImageLayer.swift +1 -0
- package/Sources/Private/CoreAnimation/Layers/LayerModel+makeAnimationLayer.swift +1 -1
- package/Sources/Private/CoreAnimation/Layers/RepeaterLayer.swift +2 -0
- package/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift +11 -13
- package/Sources/Private/CoreAnimation/Layers/SolidLayer.swift +20 -5
- package/Sources/Private/CoreAnimation/Layers/TextLayer.swift +13 -3
- package/Sources/Private/CoreAnimation/ValueProviderStore.swift +6 -4
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Diffing/Collection+Diff.swift +263 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Diffing/Diffable.swift +18 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Diffing/DiffableSection.swift +16 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Diffing/IndexChangeset.swift +187 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Diffing/SectionedChangeset.swift +32 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Logging/EpoxyLogger.swift +99 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/CallbackContextEpoxyModeled.swift +8 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModelArrayBuilder.swift +48 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModelProperty.swift +158 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModelStorage.swift +88 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/EpoxyModeled.swift +54 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Internal/AnyEpoxyModelProperty.swift +29 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Internal/ClassReference.swift +39 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/AnimatedProviding.swift +10 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/DataIDProviding.swift +57 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/DidDisplayProviding.swift +41 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/DidEndDisplayingProviding.swift +41 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/DidSelectProviding.swift +36 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/ErasedContentProviding.swift +49 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/MakeViewProviding.swift +60 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/SetBehaviorsProviding.swift +38 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/SetContentProviding.swift +38 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/StyleIDProviding.swift +37 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/TraitCollectionProviding.swift +14 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/ViewDifferentiatorProviding.swift +34 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/ViewProviding.swift +13 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/Providers/WillDisplayProviding.swift +41 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Model/ViewEpoxyModeled.swift +10 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/README.md +31 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUIHostingController.swift +46 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUIHostingView.swift +391 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUIIntrinsicContentSizeInvalidator.swift +44 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxySwiftUILayoutMargins.swift +51 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/EpoxyableView+SwiftUIView.swift +172 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/LayoutUtilities/MeasuringViewRepresentable.swift +128 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/LayoutUtilities/SwiftUIMeasurementContainer.swift +452 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/SwiftUIView.swift +148 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/UIView+SwiftUIView.swift +40 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/UIViewConfiguringSwiftUIView.swift +43 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Views/BehaviorsConfigurableView.swift +45 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Views/ContentConfigurableView.swift +36 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Views/EpoxyableView.swift +5 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Views/StyledView.swift +42 -0
- package/Sources/Private/EmbeddedLibraries/EpoxyCore/Views/ViewType.swift +51 -0
- package/Sources/Private/EmbeddedLibraries/README.md +27 -0
- package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+BackingConfiguration.swift +4 -4
- package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+MemoryFile.swift +2 -2
- package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+Writing.swift +4 -4
- package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive.swift +8 -7
- package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Data+Compression.swift +5 -5
- package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/FileManager+ZIP.swift +4 -4
- package/Sources/Private/MainThread/LayerContainers/CompLayers/ImageCompositionLayer.swift +6 -0
- package/Sources/Private/MainThread/LayerContainers/CompLayers/MaskContainerLayer.swift +3 -1
- package/Sources/Private/MainThread/LayerContainers/CompLayers/PreCompositionLayer.swift +18 -5
- package/Sources/Private/MainThread/LayerContainers/CompLayers/TextCompositionLayer.swift +31 -3
- package/Sources/Private/MainThread/LayerContainers/MainThreadAnimationLayer.swift +33 -8
- package/Sources/Private/MainThread/LayerContainers/Utility/CachedImageProvider.swift +8 -1
- package/Sources/Private/MainThread/LayerContainers/Utility/CompositionLayersInitializer.swift +13 -4
- package/Sources/Private/MainThread/LayerContainers/Utility/LayerFontProvider.swift +2 -2
- package/Sources/Private/MainThread/LayerContainers/Utility/LayerImageProvider.swift +1 -0
- package/Sources/Private/MainThread/LayerContainers/Utility/LayerTextProvider.swift +4 -4
- package/Sources/Private/MainThread/NodeRenderSystem/NodeProperties/Protocols/NodePropertyMap.swift +1 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/ModifierNodes/TrimPathNode.swift +3 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/GradientFillRenderer.swift +2 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/LegacyGradientFillRenderer.swift +2 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/GradientFillNode.swift +1 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/GradientStrokeNode.swift +2 -2
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/StrokeNode.swift +1 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/Text/TextAnimatorNode.swift +1 -1
- package/Sources/Private/MainThread/NodeRenderSystem/RenderLayers/ShapeContainerLayer.swift +6 -2
- package/Sources/Private/Model/Assets/Asset.swift +8 -0
- package/Sources/Private/Model/Assets/AssetLibrary.swift +2 -2
- package/Sources/Private/Model/Assets/ImageAsset.swift +3 -3
- package/Sources/Private/Model/DotLottie/DotLottieAnimation.swift +16 -2
- package/Sources/Private/Model/DotLottie/DotLottieImageProvider.swift +20 -7
- package/Sources/Private/Model/Extensions/KeyedDecodingContainerExtensions.swift +26 -0
- package/Sources/Private/Model/Keyframes/KeyframeGroup.swift +8 -5
- package/Sources/Private/Model/LayerEffects/DropShadowEffect.swift +45 -0
- package/Sources/Private/Model/LayerEffects/EffectValues/ColorEffectValue.swift +38 -0
- package/Sources/Private/Model/LayerEffects/EffectValues/EffectValue.swift +98 -0
- package/Sources/Private/Model/LayerEffects/EffectValues/Vector1DEffectValue.swift +38 -0
- package/Sources/Private/Model/LayerEffects/LayerEffect.swift +103 -0
- package/Sources/Private/Model/LayerStyles/DropShadowStyle.swift +72 -0
- package/Sources/Private/Model/LayerStyles/LayerStyle.swift +85 -0
- package/Sources/Private/Model/Layers/LayerModel.swift +27 -0
- package/Sources/Private/Model/Objects/Marker.swift +1 -1
- package/Sources/Private/Model/Objects/Transform.swift +1 -2
- package/Sources/Private/Model/ShapeItems/GradientFill.swift +1 -1
- package/Sources/Private/Model/ShapeItems/GradientStroke.swift +2 -2
- package/Sources/Private/Model/ShapeItems/Merge.swift +1 -1
- package/Sources/Private/Model/ShapeItems/ShapeItem.swift +31 -26
- package/Sources/Private/Model/ShapeItems/ShapeTransform.swift +0 -9
- package/Sources/Private/Model/ShapeItems/Star.swift +1 -1
- package/Sources/Private/Model/Text/Font.swift +2 -2
- package/Sources/Private/Model/Text/Glyph.swift +1 -1
- package/Sources/Private/RootAnimationLayer.swift +2 -2
- package/Sources/Private/Utility/Debugging/LayerDebugging.swift +3 -1
- package/Sources/Private/Utility/Extensions/AnimationKeypathExtension.swift +32 -2
- package/Sources/Private/Utility/Helpers/AnimationContext.swift +4 -2
- package/Sources/Private/Utility/Helpers/AnyEquatable.swift +24 -0
- package/Sources/Private/Utility/Helpers/Binding+Map.swift +18 -0
- package/Sources/Private/Utility/Helpers/View+ValueChanged.swift +20 -0
- package/Sources/Private/Utility/LottieAnimationSource.swift +41 -0
- package/Sources/Private/Utility/Primitives/BezierPath.swift +2 -2
- package/Sources/Private/Utility/Primitives/BezierPathRoundExtension.swift +2 -2
- package/Sources/Private/Utility/Primitives/VectorsExtensions.swift +1 -1
- package/Sources/Public/Animation/LottieAnimation.swift +21 -2
- package/Sources/Public/Animation/LottieAnimationLayer.swift +1464 -0
- package/Sources/Public/Animation/LottieAnimationView.swift +258 -735
- package/Sources/Public/Animation/LottiePlaybackMode.swift +117 -0
- package/Sources/Public/Animation/LottieView.swift +462 -0
- package/Sources/Public/AnimationCache/AnimationCacheProvider.swift +2 -1
- package/Sources/Public/AnimationCache/DefaultAnimationCache.swift +5 -6
- package/Sources/Public/Configuration/DecodingStrategy.swift +15 -0
- package/Sources/Public/Configuration/LottieConfiguration.swift +47 -0
- package/Sources/Public/Configuration/ReducedMotionOption.swift +114 -0
- package/Sources/Public/{LottieConfiguration.swift → Configuration/RenderingEngineOption.swift} +2 -57
- package/Sources/Public/{iOS → Controls}/AnimatedButton.swift +56 -13
- package/Sources/Public/{iOS → Controls}/AnimatedControl.swift +80 -8
- package/Sources/Public/{iOS → Controls}/AnimatedSwitch.swift +71 -31
- package/Sources/Public/Controls/LottieButton.swift +122 -0
- package/Sources/Public/Controls/LottieSwitch.swift +144 -0
- package/Sources/Public/Controls/LottieViewType.swift +79 -0
- package/Sources/Public/DotLottie/DotLottieConfiguration.swift +24 -0
- package/Sources/Public/DotLottie/DotLottieFile.swift +21 -6
- package/Sources/Public/DotLottie/DotLottieFileHelpers.swift +79 -0
- package/Sources/Public/DynamicProperties/AnimationKeypath.swift +11 -1
- package/Sources/Public/DynamicProperties/ValueProviders/ColorValueProvider.swift +14 -0
- package/Sources/Public/DynamicProperties/ValueProviders/FloatValueProvider.swift +13 -0
- package/Sources/Public/DynamicProperties/ValueProviders/GradientValueProvider.swift +22 -5
- package/Sources/Public/DynamicProperties/ValueProviders/PointValueProvider.swift +14 -0
- package/Sources/Public/DynamicProperties/ValueProviders/SizeValueProvider.swift +13 -0
- package/Sources/Public/FontProvider/AnimationFontProvider.swift +8 -0
- package/Sources/Public/ImageProvider/AnimationImageProvider.swift +24 -0
- package/Sources/Public/Keyframes/Keyframe.swift +6 -0
- package/Sources/Public/Primitives/Vectors.swift +2 -2
- package/Sources/Public/TextProvider/AnimationTextProvider.swift +79 -6
- package/Sources/Public/iOS/AnimationSubview.swift +1 -1
- package/Sources/Public/iOS/BundleImageProvider.swift +16 -2
- package/Sources/Public/iOS/Compatibility/CompatibleAnimationView.swift +2 -2
- package/Sources/Public/iOS/FilepathImageProvider.swift +22 -3
- package/Sources/Public/iOS/LottieAnimationViewBase.swift +7 -1
- package/Sources/Public/macOS/BundleImageProvider.macOS.swift +15 -1
- package/Sources/Public/macOS/FilepathImageProvider.macOS.swift +21 -2
- package/lottie-ios.podspec +2 -1
- package/package.json +1 -1
- package/Sources/Private/Model/DotLottie/DotLottieConfiguration.swift +0 -15
- /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+Helpers.swift +0 -0
- /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+Progress.swift +0 -0
- /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+Reading.swift +0 -0
- /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+ReadingDeprecated.swift +0 -0
- /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+WritingDeprecated.swift +0 -0
- /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Archive+ZIP64.swift +0 -0
- /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Data+CompressionDeprecated.swift +0 -0
- /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Data+Serialization.swift +0 -0
- /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Entry+Serialization.swift +0 -0
- /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Entry+ZIP64.swift +0 -0
- /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/Entry.swift +0 -0
- /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/README.md +0 -0
- /package/Sources/Private/{Model/DotLottie → EmbeddedLibraries}/ZipFoundation/URL+ZIP.swift +0 -0
|
@@ -54,7 +54,7 @@ public enum LottieBackgroundBehavior {
|
|
|
54
54
|
// MARK: - LottieLoopMode
|
|
55
55
|
|
|
56
56
|
/// Defines animation loop behavior
|
|
57
|
-
public enum LottieLoopMode {
|
|
57
|
+
public enum LottieLoopMode: Hashable {
|
|
58
58
|
/// Animation is played once then stops.
|
|
59
59
|
case playOnce
|
|
60
60
|
/// Animation will loop from beginning to end until stopped.
|
|
@@ -87,6 +87,8 @@ extension LottieLoopMode: Equatable {
|
|
|
87
87
|
|
|
88
88
|
// MARK: - LottieAnimationView
|
|
89
89
|
|
|
90
|
+
/// A UIView subclass for rendering Lottie animations.
|
|
91
|
+
/// - Also available as a SwiftUI view (`LottieView`) and a CALayer subclass (`LottieAnimationLayer`)
|
|
90
92
|
@IBDesignable
|
|
91
93
|
open class LottieAnimationView: LottieAnimationViewBase {
|
|
92
94
|
|
|
@@ -98,20 +100,21 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
98
100
|
public init(
|
|
99
101
|
animation: LottieAnimation?,
|
|
100
102
|
imageProvider: AnimationImageProvider? = nil,
|
|
101
|
-
textProvider:
|
|
103
|
+
textProvider: AnimationKeypathTextProvider = DefaultTextProvider(),
|
|
102
104
|
fontProvider: AnimationFontProvider = DefaultFontProvider(),
|
|
103
105
|
configuration: LottieConfiguration = .shared,
|
|
104
106
|
logger: LottieLogger = .shared)
|
|
105
107
|
{
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
108
|
+
lottieAnimationLayer = LottieAnimationLayer(
|
|
109
|
+
animation: animation,
|
|
110
|
+
imageProvider: imageProvider,
|
|
111
|
+
textProvider: textProvider,
|
|
112
|
+
fontProvider: fontProvider,
|
|
113
|
+
configuration: configuration,
|
|
114
|
+
logger: logger)
|
|
111
115
|
self.logger = logger
|
|
112
116
|
super.init(frame: .zero)
|
|
113
117
|
commonInit()
|
|
114
|
-
makeAnimationLayer(usingEngine: configuration.renderingEngine)
|
|
115
118
|
if let animation = animation {
|
|
116
119
|
frame = animation.bounds
|
|
117
120
|
}
|
|
@@ -121,23 +124,21 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
121
124
|
public init(
|
|
122
125
|
dotLottie: DotLottieFile?,
|
|
123
126
|
animationId: String? = nil,
|
|
124
|
-
textProvider:
|
|
127
|
+
textProvider: AnimationKeypathTextProvider = DefaultTextProvider(),
|
|
125
128
|
fontProvider: AnimationFontProvider = DefaultFontProvider(),
|
|
126
129
|
configuration: LottieConfiguration = .shared,
|
|
127
130
|
logger: LottieLogger = .shared)
|
|
128
131
|
{
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
132
|
+
lottieAnimationLayer = LottieAnimationLayer(
|
|
133
|
+
dotLottie: dotLottie,
|
|
134
|
+
animationId: animationId,
|
|
135
|
+
textProvider: textProvider,
|
|
136
|
+
fontProvider: fontProvider,
|
|
137
|
+
configuration: configuration,
|
|
138
|
+
logger: logger)
|
|
135
139
|
self.logger = logger
|
|
136
140
|
super.init(frame: .zero)
|
|
137
141
|
commonInit()
|
|
138
|
-
loopMode = dotLottieAnimation?.configuration.loopMode ?? .playOnce
|
|
139
|
-
animationSpeed = CGFloat(dotLottieAnimation?.configuration.speed ?? 1)
|
|
140
|
-
makeAnimationLayer(usingEngine: configuration.renderingEngine)
|
|
141
142
|
if let animation = animation {
|
|
142
143
|
frame = animation.bounds
|
|
143
144
|
}
|
|
@@ -147,54 +148,82 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
147
148
|
configuration: LottieConfiguration = .shared,
|
|
148
149
|
logger: LottieLogger = .shared)
|
|
149
150
|
{
|
|
150
|
-
|
|
151
|
-
imageProvider = BundleImageProvider(bundle: Bundle.main, searchPath: nil)
|
|
152
|
-
textProvider = DefaultTextProvider()
|
|
153
|
-
fontProvider = DefaultFontProvider()
|
|
154
|
-
self.configuration = configuration
|
|
151
|
+
lottieAnimationLayer = LottieAnimationLayer(configuration: configuration, logger: logger)
|
|
155
152
|
self.logger = logger
|
|
156
153
|
super.init(frame: .zero)
|
|
157
154
|
commonInit()
|
|
158
155
|
}
|
|
159
156
|
|
|
160
157
|
public override init(frame: CGRect) {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
158
|
+
lottieAnimationLayer = LottieAnimationLayer(
|
|
159
|
+
animation: nil,
|
|
160
|
+
imageProvider: BundleImageProvider(bundle: Bundle.main, searchPath: nil),
|
|
161
|
+
textProvider: DefaultTextProvider(),
|
|
162
|
+
fontProvider: DefaultFontProvider(),
|
|
163
|
+
configuration: .shared,
|
|
164
|
+
logger: .shared)
|
|
166
165
|
logger = .shared
|
|
167
166
|
super.init(frame: frame)
|
|
168
167
|
commonInit()
|
|
169
168
|
}
|
|
170
169
|
|
|
171
170
|
required public init?(coder aDecoder: NSCoder) {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
171
|
+
lottieAnimationLayer = LottieAnimationLayer(
|
|
172
|
+
animation: nil,
|
|
173
|
+
imageProvider: BundleImageProvider(bundle: Bundle.main, searchPath: nil),
|
|
174
|
+
textProvider: DefaultTextProvider(),
|
|
175
|
+
fontProvider: DefaultFontProvider(),
|
|
176
|
+
configuration: .shared,
|
|
177
|
+
logger: .shared)
|
|
176
178
|
logger = .shared
|
|
177
179
|
super.init(coder: aDecoder)
|
|
178
180
|
commonInit()
|
|
179
181
|
}
|
|
180
182
|
|
|
183
|
+
convenience init(
|
|
184
|
+
animationSource: LottieAnimationSource?,
|
|
185
|
+
imageProvider: AnimationImageProvider? = nil,
|
|
186
|
+
textProvider: AnimationKeypathTextProvider = DefaultTextProvider(),
|
|
187
|
+
fontProvider: AnimationFontProvider = DefaultFontProvider(),
|
|
188
|
+
configuration: LottieConfiguration = .shared,
|
|
189
|
+
logger: LottieLogger = .shared)
|
|
190
|
+
{
|
|
191
|
+
switch animationSource {
|
|
192
|
+
case .lottieAnimation(let animation):
|
|
193
|
+
self.init(
|
|
194
|
+
animation: animation,
|
|
195
|
+
imageProvider: imageProvider,
|
|
196
|
+
textProvider: textProvider,
|
|
197
|
+
fontProvider: fontProvider,
|
|
198
|
+
configuration: configuration,
|
|
199
|
+
logger: logger)
|
|
200
|
+
|
|
201
|
+
case .dotLottieFile(let dotLottieFile):
|
|
202
|
+
self.init(
|
|
203
|
+
dotLottie: dotLottieFile,
|
|
204
|
+
textProvider: textProvider,
|
|
205
|
+
fontProvider: fontProvider,
|
|
206
|
+
configuration: configuration,
|
|
207
|
+
logger: logger)
|
|
208
|
+
|
|
209
|
+
case nil:
|
|
210
|
+
self.init(
|
|
211
|
+
animation: nil,
|
|
212
|
+
imageProvider: imageProvider,
|
|
213
|
+
textProvider: textProvider,
|
|
214
|
+
fontProvider: fontProvider,
|
|
215
|
+
configuration: configuration,
|
|
216
|
+
logger: logger)
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
181
220
|
// MARK: Open
|
|
182
221
|
|
|
183
222
|
/// Plays the animation from its current state to the end.
|
|
184
223
|
///
|
|
185
224
|
/// - Parameter completion: An optional completion closure to be called when the animation completes playing.
|
|
186
225
|
open func play(completion: LottieCompletionBlock? = nil) {
|
|
187
|
-
|
|
188
|
-
return
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/// Build a context for the animation.
|
|
192
|
-
let context = AnimationContext(
|
|
193
|
-
playFrom: CGFloat(animation.startFrame),
|
|
194
|
-
playTo: CGFloat(animation.endFrame),
|
|
195
|
-
closure: completion)
|
|
196
|
-
removeCurrentAnimationIfNecessary()
|
|
197
|
-
addNewAnimationForContext(context)
|
|
226
|
+
lottieAnimationLayer.play(completion: completion)
|
|
198
227
|
}
|
|
199
228
|
|
|
200
229
|
/// Plays the animation from a progress (0-1) to a progress (0-1).
|
|
@@ -209,20 +238,7 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
209
238
|
loopMode: LottieLoopMode? = nil,
|
|
210
239
|
completion: LottieCompletionBlock? = nil)
|
|
211
240
|
{
|
|
212
|
-
|
|
213
|
-
return
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
removeCurrentAnimationIfNecessary()
|
|
217
|
-
if let loopMode = loopMode {
|
|
218
|
-
/// Set the loop mode, if one was supplied
|
|
219
|
-
self.loopMode = loopMode
|
|
220
|
-
}
|
|
221
|
-
let context = AnimationContext(
|
|
222
|
-
playFrom: animation.frameTime(forProgress: fromProgress ?? currentProgress),
|
|
223
|
-
playTo: animation.frameTime(forProgress: toProgress),
|
|
224
|
-
closure: completion)
|
|
225
|
-
addNewAnimationForContext(context)
|
|
241
|
+
lottieAnimationLayer.play(fromProgress: fromProgress, toProgress: toProgress, loopMode: loopMode, completion: completion)
|
|
226
242
|
}
|
|
227
243
|
|
|
228
244
|
/// Plays the animation from a start frame to an end frame in the animation's framerate.
|
|
@@ -237,17 +253,7 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
237
253
|
loopMode: LottieLoopMode? = nil,
|
|
238
254
|
completion: LottieCompletionBlock? = nil)
|
|
239
255
|
{
|
|
240
|
-
|
|
241
|
-
if let loopMode = loopMode {
|
|
242
|
-
/// Set the loop mode, if one was supplied
|
|
243
|
-
self.loopMode = loopMode
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
let context = AnimationContext(
|
|
247
|
-
playFrom: fromFrame ?? currentFrame,
|
|
248
|
-
playTo: toFrame,
|
|
249
|
-
closure: completion)
|
|
250
|
-
addNewAnimationForContext(context)
|
|
256
|
+
lottieAnimationLayer.play(fromFrame: fromFrame, toFrame: toFrame, loopMode: loopMode, completion: completion)
|
|
251
257
|
}
|
|
252
258
|
|
|
253
259
|
/// Plays the animation from a named marker to another marker.
|
|
@@ -272,29 +278,12 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
272
278
|
loopMode: LottieLoopMode? = nil,
|
|
273
279
|
completion: LottieCompletionBlock? = nil)
|
|
274
280
|
{
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
/// Set the loop mode, if one was supplied
|
|
282
|
-
self.loopMode = loopMode
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
let fromTime: CGFloat
|
|
286
|
-
if let fromName = fromMarker, let from = markers[fromName] {
|
|
287
|
-
fromTime = CGFloat(from.frameTime)
|
|
288
|
-
} else {
|
|
289
|
-
fromTime = currentFrame
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
let playTo = playEndMarkerFrame ? CGFloat(to.frameTime) : CGFloat(to.frameTime) - 1
|
|
293
|
-
let context = AnimationContext(
|
|
294
|
-
playFrom: fromTime,
|
|
295
|
-
playTo: playTo,
|
|
296
|
-
closure: completion)
|
|
297
|
-
addNewAnimationForContext(context)
|
|
281
|
+
lottieAnimationLayer.play(
|
|
282
|
+
fromMarker: fromMarker,
|
|
283
|
+
toMarker: toMarker,
|
|
284
|
+
playEndMarkerFrame: playEndMarkerFrame,
|
|
285
|
+
loopMode: loopMode,
|
|
286
|
+
completion: completion)
|
|
298
287
|
}
|
|
299
288
|
|
|
300
289
|
/// Plays the animation from a named marker to the end of the marker's duration.
|
|
@@ -312,39 +301,70 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
312
301
|
loopMode: LottieLoopMode? = nil,
|
|
313
302
|
completion: LottieCompletionBlock? = nil)
|
|
314
303
|
{
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
}
|
|
304
|
+
lottieAnimationLayer.play(marker: marker, loopMode: loopMode, completion: completion)
|
|
305
|
+
}
|
|
318
306
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
307
|
+
/// Plays the given markers sequentially in order.
|
|
308
|
+
///
|
|
309
|
+
/// A marker is a point in time with an associated duration that is encoded into the
|
|
310
|
+
/// animation data and assigned a name. Multiple markers can be played sequentially
|
|
311
|
+
/// to create programmable animations.
|
|
312
|
+
///
|
|
313
|
+
/// If a marker is not found, it will be skipped.
|
|
314
|
+
///
|
|
315
|
+
/// If a marker doesn't have a duration value, it will play with a duration of 0
|
|
316
|
+
/// (effectively being skipped).
|
|
317
|
+
///
|
|
318
|
+
/// If another animation is played (by calling any `play` method) while this
|
|
319
|
+
/// marker sequence is playing, the marker sequence will be cancelled.
|
|
320
|
+
///
|
|
321
|
+
/// - Parameter markers: The list of markers to play sequentially.
|
|
322
|
+
/// - Parameter completion: An optional completion closure to be called when the animation stops.
|
|
323
|
+
open func play(
|
|
324
|
+
markers: [String],
|
|
325
|
+
completion: LottieCompletionBlock? = nil)
|
|
326
|
+
{
|
|
327
|
+
lottieAnimationLayer.play(markers: markers, completion: completion)
|
|
324
328
|
}
|
|
325
329
|
|
|
326
330
|
/// Stops the animation and resets the view to its start frame.
|
|
327
331
|
///
|
|
328
332
|
/// The completion closure will be called with `false`
|
|
329
333
|
open func stop() {
|
|
330
|
-
|
|
331
|
-
currentFrame = 0
|
|
334
|
+
lottieAnimationLayer.stop()
|
|
332
335
|
}
|
|
333
336
|
|
|
334
337
|
/// Pauses the animation in its current state.
|
|
335
338
|
///
|
|
336
339
|
/// The completion closure will be called with `false`
|
|
337
340
|
open func pause() {
|
|
338
|
-
|
|
341
|
+
lottieAnimationLayer.pause()
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/// Applies the given `LottiePlaybackMode` to this layer.
|
|
345
|
+
/// - Parameter animationCompletionHandler: A closure that is called after
|
|
346
|
+
/// an animation triggered by this method completes. This completion
|
|
347
|
+
/// handler is **not called** after setting the playback mode to a
|
|
348
|
+
/// mode that doesn't animate (e.g. `progress`, `frame`, `time`, or `pause`).
|
|
349
|
+
open func play(
|
|
350
|
+
_ playbackMode: LottiePlaybackMode,
|
|
351
|
+
animationCompletionHandler: LottieCompletionBlock? = nil)
|
|
352
|
+
{
|
|
353
|
+
lottieAnimationLayer.play(playbackMode, animationCompletionHandler: animationCompletionHandler)
|
|
339
354
|
}
|
|
340
355
|
|
|
341
356
|
// MARK: Public
|
|
342
357
|
|
|
343
358
|
/// The configuration that this `LottieAnimationView` uses when playing its animation
|
|
344
|
-
public
|
|
359
|
+
public var configuration: LottieConfiguration {
|
|
360
|
+
get { lottieAnimationLayer.configuration }
|
|
361
|
+
set { lottieAnimationLayer.configuration = newValue }
|
|
362
|
+
}
|
|
345
363
|
|
|
346
364
|
/// Value Providers that have been registered using `setValueProvider(_:keypath:)`
|
|
347
|
-
public
|
|
365
|
+
public var valueProviders: [AnimationKeypath: AnyValueProvider] {
|
|
366
|
+
lottieAnimationLayer.valueProviders
|
|
367
|
+
}
|
|
348
368
|
|
|
349
369
|
/// Describes the behavior of an AnimationView when the app is moved to the background.
|
|
350
370
|
///
|
|
@@ -357,39 +377,16 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
357
377
|
/// The default for the Core Animation engine is `continuePlaying`,
|
|
358
378
|
/// since the Core Animation engine does not have any CPU overhead.
|
|
359
379
|
public var backgroundBehavior: LottieBackgroundBehavior {
|
|
360
|
-
get {
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
if
|
|
364
|
-
currentRenderingEngine == .mainThread,
|
|
365
|
-
_backgroundBehavior == .continuePlaying
|
|
366
|
-
{
|
|
367
|
-
logger.assertionFailure("""
|
|
368
|
-
`LottieBackgroundBehavior.continuePlaying` should not be used with the Main Thread
|
|
369
|
-
rendering engine, since this would waste CPU resources on playing an animation
|
|
370
|
-
that is not visible. Consider using a different background mode, or switching to
|
|
371
|
-
the Core Animation rendering engine (which does not have any CPU overhead).
|
|
372
|
-
""")
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
return currentBackgroundBehavior
|
|
376
|
-
}
|
|
377
|
-
set {
|
|
378
|
-
_backgroundBehavior = newValue
|
|
379
|
-
}
|
|
380
|
+
get { lottieAnimationLayer.backgroundBehavior }
|
|
381
|
+
set { lottieAnimationLayer.backgroundBehavior = newValue }
|
|
380
382
|
}
|
|
381
383
|
|
|
382
384
|
/// Sets the animation backing the animation view. Setting this will clear the
|
|
383
385
|
/// view's contents, completion blocks and current state. The new animation will
|
|
384
386
|
/// be loaded up and set to the beginning of its timeline.
|
|
385
387
|
public var animation: LottieAnimation? {
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
if let animation = animation {
|
|
390
|
-
animationLoaded?(self, animation)
|
|
391
|
-
}
|
|
392
|
-
}
|
|
388
|
+
get { lottieAnimationLayer.animation }
|
|
389
|
+
set { lottieAnimationLayer.animation = newValue }
|
|
393
390
|
}
|
|
394
391
|
|
|
395
392
|
/// A closure that is called when `self.animation` is loaded. When setting this closure,
|
|
@@ -432,58 +429,44 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
432
429
|
///
|
|
433
430
|
/// Setting this will cause the animation to reload its image contents.
|
|
434
431
|
public var imageProvider: AnimationImageProvider {
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
reloadImages()
|
|
438
|
-
}
|
|
432
|
+
get { lottieAnimationLayer.imageProvider }
|
|
433
|
+
set { lottieAnimationLayer.imageProvider = newValue }
|
|
439
434
|
}
|
|
440
435
|
|
|
441
436
|
/// Sets the text provider for animation view. A text provider provides the
|
|
442
437
|
/// animation with values for text layers
|
|
443
|
-
public var textProvider:
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
}
|
|
438
|
+
public var textProvider: AnimationKeypathTextProvider {
|
|
439
|
+
get { lottieAnimationLayer.textProvider }
|
|
440
|
+
set { lottieAnimationLayer.textProvider = newValue }
|
|
447
441
|
}
|
|
448
442
|
|
|
449
443
|
/// Sets the text provider for animation view. A text provider provides the
|
|
450
444
|
/// animation with values for text layers
|
|
451
445
|
public var fontProvider: AnimationFontProvider {
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
}
|
|
446
|
+
get { lottieAnimationLayer.fontProvider }
|
|
447
|
+
set { lottieAnimationLayer.fontProvider = newValue }
|
|
455
448
|
}
|
|
456
449
|
|
|
457
450
|
/// Whether or not the animation is masked to the bounds. Defaults to true.
|
|
458
|
-
public var maskAnimationToBounds
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
}
|
|
451
|
+
public var maskAnimationToBounds: Bool {
|
|
452
|
+
get { lottieAnimationLayer.maskAnimationToBounds }
|
|
453
|
+
set { lottieAnimationLayer.maskAnimationToBounds = newValue }
|
|
462
454
|
}
|
|
463
455
|
|
|
464
456
|
/// Returns `true` if the animation is currently playing.
|
|
465
457
|
public var isAnimationPlaying: Bool {
|
|
466
|
-
|
|
467
|
-
return false
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
if let valueFromLayer = animationLayer.isAnimationPlaying {
|
|
471
|
-
return valueFromLayer
|
|
472
|
-
} else {
|
|
473
|
-
return animationLayer.animation(forKey: activeAnimationName) != nil
|
|
474
|
-
}
|
|
458
|
+
lottieAnimationLayer.isAnimationPlaying
|
|
475
459
|
}
|
|
476
460
|
|
|
477
461
|
/// Returns `true` if the animation will start playing when this view is added to a window.
|
|
478
462
|
public var isAnimationQueued: Bool {
|
|
479
|
-
|
|
463
|
+
lottieAnimationLayer.hasAnimationContext && waitingToPlayAnimation
|
|
480
464
|
}
|
|
481
465
|
|
|
482
466
|
/// Sets the loop behavior for `play` calls. Defaults to `playOnce`
|
|
483
|
-
public var loopMode: LottieLoopMode
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
}
|
|
467
|
+
public var loopMode: LottieLoopMode {
|
|
468
|
+
get { lottieAnimationLayer.loopMode }
|
|
469
|
+
set { lottieAnimationLayer.loopMode = newValue }
|
|
487
470
|
}
|
|
488
471
|
|
|
489
472
|
/// When `true` the animation view will rasterize its contents when not animating.
|
|
@@ -492,10 +475,9 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
492
475
|
/// Note: this will not produce crisp results at resolutions above the animations natural resolution.
|
|
493
476
|
///
|
|
494
477
|
/// Defaults to `false`
|
|
495
|
-
public var shouldRasterizeWhenIdle
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
}
|
|
478
|
+
public var shouldRasterizeWhenIdle: Bool {
|
|
479
|
+
get { lottieAnimationLayer.shouldRasterizeWhenIdle }
|
|
480
|
+
set { lottieAnimationLayer.shouldRasterizeWhenIdle = newValue }
|
|
499
481
|
}
|
|
500
482
|
|
|
501
483
|
/// Sets the current animation time with a Progress Time
|
|
@@ -503,20 +485,8 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
503
485
|
/// Note: Setting this will stop the current animation, if any.
|
|
504
486
|
/// Note 2: If `animation` is nil, setting this will fallback to 0
|
|
505
487
|
public var currentProgress: AnimationProgressTime {
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
currentFrame = animation.frameTime(forProgress: newValue)
|
|
509
|
-
} else {
|
|
510
|
-
currentFrame = 0
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
get {
|
|
514
|
-
if let animation = animation {
|
|
515
|
-
return animation.progressTime(forFrame: currentFrame)
|
|
516
|
-
} else {
|
|
517
|
-
return 0
|
|
518
|
-
}
|
|
519
|
-
}
|
|
488
|
+
get { lottieAnimationLayer.currentProgress }
|
|
489
|
+
set { lottieAnimationLayer.currentProgress = newValue }
|
|
520
490
|
}
|
|
521
491
|
|
|
522
492
|
/// Sets the current animation time with a time in seconds.
|
|
@@ -524,53 +494,32 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
524
494
|
/// Note: Setting this will stop the current animation, if any.
|
|
525
495
|
/// Note 2: If `animation` is nil, setting this will fallback to 0
|
|
526
496
|
public var currentTime: TimeInterval {
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
currentFrame = animation.frameTime(forTime: newValue)
|
|
530
|
-
} else {
|
|
531
|
-
currentFrame = 0
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
get {
|
|
535
|
-
if let animation = animation {
|
|
536
|
-
return animation.time(forFrame: currentFrame)
|
|
537
|
-
} else {
|
|
538
|
-
return 0
|
|
539
|
-
}
|
|
540
|
-
}
|
|
497
|
+
get { lottieAnimationLayer.currentTime }
|
|
498
|
+
set { lottieAnimationLayer.currentTime = newValue }
|
|
541
499
|
}
|
|
542
500
|
|
|
543
501
|
/// Sets the current animation time with a frame in the animations framerate.
|
|
544
502
|
///
|
|
545
503
|
/// Note: Setting this will stop the current animation, if any.
|
|
546
504
|
public var currentFrame: AnimationFrameTime {
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
updateAnimationFrame(newValue)
|
|
550
|
-
}
|
|
551
|
-
get {
|
|
552
|
-
animationLayer?.currentFrame ?? 0
|
|
553
|
-
}
|
|
505
|
+
get { lottieAnimationLayer.currentFrame }
|
|
506
|
+
set { lottieAnimationLayer.currentFrame = newValue }
|
|
554
507
|
}
|
|
555
508
|
|
|
556
509
|
/// Returns the current animation frame while an animation is playing.
|
|
557
510
|
public var realtimeAnimationFrame: AnimationFrameTime {
|
|
558
|
-
|
|
511
|
+
lottieAnimationLayer.realtimeAnimationFrame
|
|
559
512
|
}
|
|
560
513
|
|
|
561
514
|
/// Returns the current animation frame while an animation is playing.
|
|
562
515
|
public var realtimeAnimationProgress: AnimationProgressTime {
|
|
563
|
-
|
|
564
|
-
return animation.progressTime(forFrame: realtimeAnimationFrame)
|
|
565
|
-
}
|
|
566
|
-
return 0
|
|
516
|
+
lottieAnimationLayer.realtimeAnimationProgress
|
|
567
517
|
}
|
|
568
518
|
|
|
569
519
|
/// Sets the speed of the animation playback. Defaults to 1
|
|
570
|
-
public var animationSpeed: CGFloat
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
}
|
|
520
|
+
public var animationSpeed: CGFloat {
|
|
521
|
+
get { lottieAnimationLayer.animationSpeed }
|
|
522
|
+
set { lottieAnimationLayer.animationSpeed = newValue }
|
|
574
523
|
}
|
|
575
524
|
|
|
576
525
|
/// When `true` the animation will play back at the framerate encoded in the
|
|
@@ -578,10 +527,9 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
578
527
|
/// of the device.
|
|
579
528
|
///
|
|
580
529
|
/// Defaults to false
|
|
581
|
-
public var respectAnimationFrameRate
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
}
|
|
530
|
+
public var respectAnimationFrameRate: Bool {
|
|
531
|
+
get { lottieAnimationLayer.respectAnimationFrameRate }
|
|
532
|
+
set { lottieAnimationLayer.respectAnimationFrameRate = newValue }
|
|
585
533
|
}
|
|
586
534
|
|
|
587
535
|
/// Controls the cropping of an Animation. Setting this property will crop the animation
|
|
@@ -589,7 +537,7 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
589
537
|
/// in the animation's coordinate space.
|
|
590
538
|
///
|
|
591
539
|
/// Animatable.
|
|
592
|
-
public var viewportFrame: CGRect?
|
|
540
|
+
public var viewportFrame: CGRect? {
|
|
593
541
|
didSet {
|
|
594
542
|
// This is really ugly, but is needed to trigger a layout pass within an animation block.
|
|
595
543
|
// Typically this happens automatically, when layout objects are UIView based.
|
|
@@ -607,7 +555,7 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
607
555
|
}
|
|
608
556
|
|
|
609
557
|
override public var intrinsicContentSize: CGSize {
|
|
610
|
-
if let animation = animation {
|
|
558
|
+
if let animation = lottieAnimationLayer.animation {
|
|
611
559
|
return animation.bounds.size
|
|
612
560
|
}
|
|
613
561
|
return .zero
|
|
@@ -617,21 +565,25 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
617
565
|
/// - This will only be `nil` in cases where the configuration is `automatic`
|
|
618
566
|
/// but a `RootAnimationLayer` hasn't been constructed yet
|
|
619
567
|
public var currentRenderingEngine: RenderingEngine? {
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
return engine
|
|
568
|
+
lottieAnimationLayer.currentRenderingEngine
|
|
569
|
+
}
|
|
623
570
|
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
571
|
+
/// The current `LottiePlaybackMode` that is being used
|
|
572
|
+
public var currentPlaybackMode: LottiePlaybackMode? {
|
|
573
|
+
lottieAnimationLayer.currentPlaybackMode
|
|
574
|
+
}
|
|
628
575
|
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
576
|
+
/// Whether or not the Main Thread rendering engine should use `forceDisplayUpdate()`
|
|
577
|
+
/// when rendering each individual frame.
|
|
578
|
+
/// - The main thread rendering engine implements optimizations to decrease the amount
|
|
579
|
+
/// of properties that have to be re-rendered on each frame. There are some cases
|
|
580
|
+
/// where this can result in bugs / incorrect behavior, so we allow it to be disabled.
|
|
581
|
+
/// - Forcing a full render on every frame will decrease performance, and is not recommended
|
|
582
|
+
/// except as a workaround to a bug in the main thread rendering engine.
|
|
583
|
+
/// - Has no effect when using the Core Animation rendering engine.
|
|
584
|
+
public var mainThreadRenderingEngineShouldForceDisplayUpdateOnEachFrame: Bool {
|
|
585
|
+
get { lottieAnimationLayer.mainThreadRenderingEngineShouldForceDisplayUpdateOnEachFrame }
|
|
586
|
+
set { lottieAnimationLayer.mainThreadRenderingEngineShouldForceDisplayUpdateOnEachFrame = newValue }
|
|
635
587
|
}
|
|
636
588
|
|
|
637
589
|
/// Sets the lottie file backing the animation view. Setting this will clear the
|
|
@@ -647,26 +599,33 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
647
599
|
_ animationId: String? = nil,
|
|
648
600
|
from dotLottieFile: DotLottieFile)
|
|
649
601
|
{
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
loopMode = dotLottieAnimation.configuration.loopMode
|
|
653
|
-
animationSpeed = CGFloat(dotLottieAnimation.configuration.speed)
|
|
654
|
-
|
|
655
|
-
if let imageProvider = dotLottieAnimation.configuration.imageProvider {
|
|
656
|
-
self.imageProvider = imageProvider
|
|
657
|
-
}
|
|
602
|
+
lottieAnimationLayer.loadAnimation(animationId, from: dotLottieFile)
|
|
603
|
+
}
|
|
658
604
|
|
|
659
|
-
|
|
605
|
+
/// Sets the lottie file backing the animation view. Setting this will clear the
|
|
606
|
+
/// view's contents, completion blocks and current state. The new animation will
|
|
607
|
+
/// be loaded up and set to the beginning of its timeline.
|
|
608
|
+
/// The loopMode, animationSpeed and imageProvider will be set according
|
|
609
|
+
/// to lottie file settings
|
|
610
|
+
/// - Parameters:
|
|
611
|
+
/// - atIndex: Internal animation index to play. Optional
|
|
612
|
+
/// Defaults to play first animation in file.
|
|
613
|
+
/// - dotLottieFile: Lottie file to play
|
|
614
|
+
public func loadAnimation(
|
|
615
|
+
atIndex index: Int,
|
|
616
|
+
from dotLottieFile: DotLottieFile)
|
|
617
|
+
{
|
|
618
|
+
lottieAnimationLayer.loadAnimation(atIndex: index, from: dotLottieFile)
|
|
660
619
|
}
|
|
661
620
|
|
|
662
621
|
/// Reloads the images supplied to the animation from the `imageProvider`
|
|
663
622
|
public func reloadImages() {
|
|
664
|
-
|
|
623
|
+
lottieAnimationLayer.reloadImages()
|
|
665
624
|
}
|
|
666
625
|
|
|
667
626
|
/// Forces the LottieAnimationView to redraw its contents.
|
|
668
627
|
public func forceDisplayUpdate() {
|
|
669
|
-
|
|
628
|
+
lottieAnimationLayer.forceDisplayUpdate()
|
|
670
629
|
}
|
|
671
630
|
|
|
672
631
|
/// Sets a ValueProvider for the specified keypath. The value provider will be set
|
|
@@ -692,10 +651,7 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
692
651
|
/// animationView.setValueProvider(redValueProvider, keypath: fillKeypath)
|
|
693
652
|
/// ```
|
|
694
653
|
public func setValueProvider(_ valueProvider: AnyValueProvider, keypath: AnimationKeypath) {
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
valueProviders[keypath] = valueProvider
|
|
698
|
-
animationLayer.setValueProvider(valueProvider, keypath: keypath)
|
|
654
|
+
lottieAnimationLayer.setValueProvider(valueProvider, keypath: keypath)
|
|
699
655
|
}
|
|
700
656
|
|
|
701
657
|
/// Reads the value of a property specified by the Keypath.
|
|
@@ -704,7 +660,7 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
704
660
|
/// - Parameter for: The keypath used to search for the property.
|
|
705
661
|
/// - Parameter atFrame: The Frame Time of the value to query. If nil then the current frame is used.
|
|
706
662
|
public func getValue(for keypath: AnimationKeypath, atFrame: AnimationFrameTime?) -> Any? {
|
|
707
|
-
|
|
663
|
+
lottieAnimationLayer.getValue(for: keypath, atFrame: atFrame)
|
|
708
664
|
}
|
|
709
665
|
|
|
710
666
|
/// Reads the original value of a property specified by the Keypath.
|
|
@@ -714,19 +670,19 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
714
670
|
/// - Parameter for: The keypath used to search for the property.
|
|
715
671
|
/// - Parameter atFrame: The Frame Time of the value to query. If nil then the current frame is used.
|
|
716
672
|
public func getOriginalValue(for keypath: AnimationKeypath, atFrame: AnimationFrameTime?) -> Any? {
|
|
717
|
-
|
|
673
|
+
lottieAnimationLayer.getOriginalValue(for: keypath, atFrame: atFrame)
|
|
718
674
|
}
|
|
719
675
|
|
|
720
676
|
/// Logs all child keypaths.
|
|
721
677
|
/// Logs the result of `allHierarchyKeypaths()` to the `LottieLogger`.
|
|
722
678
|
public func logHierarchyKeypaths() {
|
|
723
|
-
|
|
679
|
+
lottieAnimationLayer.logHierarchyKeypaths()
|
|
724
680
|
}
|
|
725
681
|
|
|
726
682
|
/// Computes and returns a list of all child keypaths in the current animation.
|
|
727
683
|
/// The returned list is the same as the log output of `logHierarchyKeypaths()`
|
|
728
684
|
public func allHierarchyKeypaths() -> [String] {
|
|
729
|
-
|
|
685
|
+
lottieAnimationLayer.allHierarchyKeypaths()
|
|
730
686
|
}
|
|
731
687
|
|
|
732
688
|
/// Searches for the nearest child layer to the first Keypath and adds the subview
|
|
@@ -751,12 +707,12 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
751
707
|
/// animationView.addSubview(subview, forLayerAt: layerKeypath)
|
|
752
708
|
/// ```
|
|
753
709
|
public func addSubview(_ subview: AnimationSubview, forLayerAt keypath: AnimationKeypath) {
|
|
754
|
-
guard let sublayer =
|
|
710
|
+
guard let sublayer = lottieAnimationLayer.rootAnimationLayer?.layer(for: keypath) else {
|
|
755
711
|
return
|
|
756
712
|
}
|
|
757
713
|
setNeedsLayout()
|
|
758
714
|
layoutIfNeeded()
|
|
759
|
-
forceDisplayUpdate()
|
|
715
|
+
lottieAnimationLayer.forceDisplayUpdate()
|
|
760
716
|
addSubview(subview)
|
|
761
717
|
if let subViewLayer = subview.viewLayer {
|
|
762
718
|
sublayer.addSublayer(subViewLayer)
|
|
@@ -771,17 +727,10 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
771
727
|
/// - Parameter rect: The CGRect to convert.
|
|
772
728
|
/// - Parameter toLayerAt: The keypath used to find the layer.
|
|
773
729
|
public func convert(_ rect: CGRect, toLayerAt keypath: AnimationKeypath?) -> CGRect? {
|
|
774
|
-
|
|
775
|
-
guard let keypath = keypath else {
|
|
776
|
-
return viewLayer?.convert(rect, to: animationLayer)
|
|
777
|
-
}
|
|
778
|
-
guard let sublayer = animationLayer.layer(for: keypath) else {
|
|
779
|
-
return nil
|
|
780
|
-
}
|
|
730
|
+
let convertedRect = lottieAnimationLayer.convert(rect, toLayerAt: keypath)
|
|
781
731
|
setNeedsLayout()
|
|
782
732
|
layoutIfNeeded()
|
|
783
|
-
|
|
784
|
-
return animationLayer.convert(rect, to: sublayer)
|
|
733
|
+
return convertedRect
|
|
785
734
|
}
|
|
786
735
|
|
|
787
736
|
/// Converts a CGPoint from the LottieAnimationView's coordinate space into the
|
|
@@ -792,17 +741,10 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
792
741
|
/// - Parameter point: The CGPoint to convert.
|
|
793
742
|
/// - Parameter toLayerAt: The keypath used to find the layer.
|
|
794
743
|
public func convert(_ point: CGPoint, toLayerAt keypath: AnimationKeypath?) -> CGPoint? {
|
|
795
|
-
|
|
796
|
-
guard let keypath = keypath else {
|
|
797
|
-
return viewLayer?.convert(point, to: animationLayer)
|
|
798
|
-
}
|
|
799
|
-
guard let sublayer = animationLayer.layer(for: keypath) else {
|
|
800
|
-
return nil
|
|
801
|
-
}
|
|
744
|
+
let convertedRect = lottieAnimationLayer.convert(point, toLayerAt: keypath)
|
|
802
745
|
setNeedsLayout()
|
|
803
746
|
layoutIfNeeded()
|
|
804
|
-
|
|
805
|
-
return animationLayer.convert(point, to: sublayer)
|
|
747
|
+
return convertedRect
|
|
806
748
|
}
|
|
807
749
|
|
|
808
750
|
/// Sets the enabled state of all animator nodes found with the keypath search.
|
|
@@ -811,14 +753,7 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
811
753
|
/// - Parameter isEnabled: When true the animator nodes affect the rendering tree. When false the node is removed from the tree.
|
|
812
754
|
/// - Parameter keypath: The keypath used to find the node(s).
|
|
813
755
|
public func setNodeIsEnabled(isEnabled: Bool, keypath: AnimationKeypath) {
|
|
814
|
-
|
|
815
|
-
let nodes = animationLayer.animatorNodes(for: keypath)
|
|
816
|
-
if let nodes = nodes {
|
|
817
|
-
for node in nodes {
|
|
818
|
-
node.isEnabled = isEnabled
|
|
819
|
-
}
|
|
820
|
-
forceDisplayUpdate()
|
|
821
|
-
}
|
|
756
|
+
lottieAnimationLayer.setNodeIsEnabled(isEnabled: isEnabled, keypath: keypath)
|
|
822
757
|
}
|
|
823
758
|
|
|
824
759
|
/// Markers are a way to describe a point in time by a key name.
|
|
@@ -830,10 +765,7 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
830
765
|
///
|
|
831
766
|
/// Returns the Progress Time for the marker named. Returns nil if no marker found.
|
|
832
767
|
public func progressTime(forMarker named: String) -> AnimationProgressTime? {
|
|
833
|
-
|
|
834
|
-
return nil
|
|
835
|
-
}
|
|
836
|
-
return animation.progressTime(forMarker: named)
|
|
768
|
+
lottieAnimationLayer.progressTime(forMarker: named)
|
|
837
769
|
}
|
|
838
770
|
|
|
839
771
|
/// Markers are a way to describe a point in time by a key name.
|
|
@@ -845,10 +777,7 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
845
777
|
///
|
|
846
778
|
/// Returns the Frame Time for the marker named. Returns nil if no marker found.
|
|
847
779
|
public func frameTime(forMarker named: String) -> AnimationFrameTime? {
|
|
848
|
-
|
|
849
|
-
return nil
|
|
850
|
-
}
|
|
851
|
-
return animation.frameTime(forMarker: named)
|
|
780
|
+
lottieAnimationLayer.frameTime(forMarker: named)
|
|
852
781
|
}
|
|
853
782
|
|
|
854
783
|
/// Markers are a way to describe a point in time and a duration by a key name.
|
|
@@ -860,32 +789,51 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
860
789
|
///
|
|
861
790
|
/// - Returns: The duration frame time for the marker, or `nil` if no marker found.
|
|
862
791
|
public func durationFrameTime(forMarker named: String) -> AnimationFrameTime? {
|
|
863
|
-
|
|
864
|
-
return nil
|
|
865
|
-
}
|
|
866
|
-
return animation.durationFrameTime(forMarker: named)
|
|
792
|
+
lottieAnimationLayer.durationFrameTime(forMarker: named)
|
|
867
793
|
}
|
|
868
794
|
|
|
869
795
|
// MARK: Internal
|
|
870
796
|
|
|
871
|
-
var animationLayer: RootAnimationLayer?
|
|
797
|
+
var animationLayer: RootAnimationLayer? {
|
|
798
|
+
lottieAnimationLayer.rootAnimationLayer
|
|
799
|
+
}
|
|
872
800
|
|
|
873
801
|
/// Set animation name from Interface Builder
|
|
874
802
|
@IBInspectable var animationName: String? {
|
|
875
803
|
didSet {
|
|
876
|
-
self.animation = animationName.flatMap {
|
|
877
|
-
LottieAnimation.named($0, animationCache: nil)
|
|
804
|
+
self.lottieAnimationLayer.animation = animationName.flatMap { LottieAnimation.named($0, animationCache: nil)
|
|
878
805
|
}
|
|
879
806
|
}
|
|
880
807
|
}
|
|
881
808
|
|
|
809
|
+
override func commonInit() {
|
|
810
|
+
super.commonInit()
|
|
811
|
+
lottieAnimationLayer.screenScale = screenScale
|
|
812
|
+
viewLayer?.addSublayer(lottieAnimationLayer)
|
|
813
|
+
|
|
814
|
+
lottieAnimationLayer.animationLoaded = { [weak self] _, animation in
|
|
815
|
+
guard let self = self else { return }
|
|
816
|
+
self.animationLoaded?(self, animation)
|
|
817
|
+
self.invalidateIntrinsicContentSize()
|
|
818
|
+
self.setNeedsLayout()
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
lottieAnimationLayer.animationLayerDidLoad = { [weak self] _, _ in
|
|
822
|
+
guard let self = self else { return }
|
|
823
|
+
self.invalidateIntrinsicContentSize()
|
|
824
|
+
self.setNeedsLayout()
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
|
|
882
828
|
override func layoutAnimation() {
|
|
883
|
-
guard let animation = animation, let animationLayer = animationLayer else { return }
|
|
829
|
+
guard let animation = lottieAnimationLayer.animation, let animationLayer = lottieAnimationLayer.animationLayer else { return }
|
|
830
|
+
|
|
884
831
|
var position = animation.bounds.center
|
|
885
832
|
let xform: CATransform3D
|
|
886
833
|
var shouldForceUpdates = false
|
|
887
834
|
|
|
888
835
|
if let viewportFrame = viewportFrame {
|
|
836
|
+
setNeedsLayout()
|
|
889
837
|
shouldForceUpdates = contentMode == .redraw
|
|
890
838
|
|
|
891
839
|
let compAspect = viewportFrame.size.width / viewportFrame.size.height
|
|
@@ -904,7 +852,7 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
904
852
|
xform = CATransform3DMakeScale(
|
|
905
853
|
bounds.size.width / animation.size.width,
|
|
906
854
|
bounds.size.height / animation.size.height,
|
|
907
|
-
1)
|
|
855
|
+
1)
|
|
908
856
|
case .scaleAspectFit:
|
|
909
857
|
position = bounds.center
|
|
910
858
|
let compAspect = animation.size.width / animation.size.height
|
|
@@ -955,7 +903,7 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
955
903
|
position.y = bounds.maxY - animation.bounds.midY
|
|
956
904
|
xform = CATransform3DIdentity
|
|
957
905
|
|
|
958
|
-
#if
|
|
906
|
+
#if canImport(UIKit)
|
|
959
907
|
@unknown default:
|
|
960
908
|
logger.assertionFailure("unsupported contentMode: \(contentMode.rawValue)")
|
|
961
909
|
xform = CATransform3DIdentity
|
|
@@ -969,7 +917,7 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
969
917
|
// If layout is changed without animation, explicitly set animation duration to 0.0
|
|
970
918
|
// inside CATransaction to avoid unwanted artifacts.
|
|
971
919
|
/// Check if any animation exist on the view's layer, and match it.
|
|
972
|
-
if let key =
|
|
920
|
+
if let key = lottieAnimationLayer.animationKeys()?.first, let animation = lottieAnimationLayer.animation(forKey: key) {
|
|
973
921
|
// The layout is happening within an animation block. Grab the animation data.
|
|
974
922
|
|
|
975
923
|
let positionKey = "LayoutPositionAnimation"
|
|
@@ -993,11 +941,7 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
993
941
|
|
|
994
942
|
animationLayer.position = position
|
|
995
943
|
animationLayer.transform = xform
|
|
996
|
-
|
|
997
|
-
animationLayer.anchorPoint = layer?.anchorPoint ?? CGPoint.zero
|
|
998
|
-
#else
|
|
999
|
-
animationLayer.anchorPoint = layer.anchorPoint
|
|
1000
|
-
#endif
|
|
944
|
+
animationLayer.anchorPoint = lottieAnimationLayer.anchorPoint
|
|
1001
945
|
animationLayer.add(positionAnimation, forKey: positionKey)
|
|
1002
946
|
animationLayer.add(xformAnimation, forKey: transformKey)
|
|
1003
947
|
} else {
|
|
@@ -1020,38 +964,21 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
1020
964
|
}
|
|
1021
965
|
|
|
1022
966
|
if shouldForceUpdates {
|
|
1023
|
-
|
|
967
|
+
lottieAnimationLayer.forceDisplayUpdate()
|
|
1024
968
|
}
|
|
1025
969
|
}
|
|
1026
970
|
|
|
1027
971
|
func updateRasterizationState() {
|
|
1028
|
-
if isAnimationPlaying {
|
|
1029
|
-
animationLayer?.shouldRasterize = false
|
|
972
|
+
if lottieAnimationLayer.isAnimationPlaying {
|
|
973
|
+
lottieAnimationLayer.animationLayer?.shouldRasterize = false
|
|
1030
974
|
} else {
|
|
1031
|
-
animationLayer?.shouldRasterize = shouldRasterizeWhenIdle
|
|
975
|
+
lottieAnimationLayer.animationLayer?.shouldRasterize = lottieAnimationLayer.shouldRasterizeWhenIdle
|
|
1032
976
|
}
|
|
1033
977
|
}
|
|
1034
978
|
|
|
1035
979
|
/// Updates the animation frame. Does not affect any current animations
|
|
1036
980
|
func updateAnimationFrame(_ newFrame: CGFloat) {
|
|
1037
|
-
|
|
1038
|
-
// in a `CATransaction` in order for the layers to be deallocated at
|
|
1039
|
-
// the correct time. The `CATransaction`s in this method interfere
|
|
1040
|
-
// with the ones managed by the performance test, and aren't actually
|
|
1041
|
-
// necessary in a headless environment, so we disable them.
|
|
1042
|
-
if TestHelpers.performanceTestsAreRunning {
|
|
1043
|
-
animationLayer?.currentFrame = newFrame
|
|
1044
|
-
animationLayer?.forceDisplayUpdate()
|
|
1045
|
-
return
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
|
-
CATransaction.begin()
|
|
1049
|
-
CATransaction.setCompletionBlock {
|
|
1050
|
-
self.animationLayer?.forceDisplayUpdate()
|
|
1051
|
-
}
|
|
1052
|
-
CATransaction.setDisableActions(true)
|
|
1053
|
-
animationLayer?.currentFrame = newFrame
|
|
1054
|
-
CATransaction.commit()
|
|
981
|
+
lottieAnimationLayer.updateAnimationFrame(newFrame)
|
|
1055
982
|
}
|
|
1056
983
|
|
|
1057
984
|
@objc
|
|
@@ -1076,438 +1003,34 @@ open class LottieAnimationView: LottieAnimationViewBase {
|
|
|
1076
1003
|
}
|
|
1077
1004
|
}
|
|
1078
1005
|
|
|
1079
|
-
/// Updates an in flight animation.
|
|
1080
1006
|
func updateInFlightAnimation() {
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
guard animationContext.closure.animationState != .complete else {
|
|
1084
|
-
// Tried to re-add an already completed animation. Cancel.
|
|
1085
|
-
self.animationContext = nil
|
|
1086
|
-
return
|
|
1087
|
-
}
|
|
1088
|
-
|
|
1089
|
-
/// Tell existing context to ignore its closure
|
|
1090
|
-
animationContext.closure.ignoreDelegate = true
|
|
1091
|
-
|
|
1092
|
-
/// Make a new context, stealing the completion block from the previous.
|
|
1093
|
-
let newContext = AnimationContext(
|
|
1094
|
-
playFrom: animationContext.playFrom,
|
|
1095
|
-
playTo: animationContext.playTo,
|
|
1096
|
-
closure: animationContext.closure.completionBlock)
|
|
1097
|
-
|
|
1098
|
-
/// Remove current animation, and freeze the current frame.
|
|
1099
|
-
let pauseFrame = realtimeAnimationFrame
|
|
1100
|
-
animationLayer?.removeAnimation(forKey: activeAnimationName)
|
|
1101
|
-
animationLayer?.currentFrame = pauseFrame
|
|
1007
|
+
lottieAnimationLayer.updateInFlightAnimation()
|
|
1008
|
+
}
|
|
1102
1009
|
|
|
1103
|
-
|
|
1010
|
+
func loadAnimation(_ animationSource: LottieAnimationSource?) {
|
|
1011
|
+
lottieAnimationLayer.loadAnimation(animationSource)
|
|
1104
1012
|
}
|
|
1105
1013
|
|
|
1106
1014
|
// MARK: Fileprivate
|
|
1107
1015
|
|
|
1108
|
-
/// Context describing the animation that is currently playing in this `LottieAnimationView`
|
|
1109
|
-
/// - When non-nil, an animation is currently playing in this view. Otherwise,
|
|
1110
|
-
/// the view is paused on a specific frame.
|
|
1111
|
-
fileprivate var animationContext: AnimationContext?
|
|
1112
|
-
|
|
1113
|
-
fileprivate var _activeAnimationName: String = LottieAnimationView.animationName
|
|
1114
|
-
fileprivate var animationID = 0
|
|
1115
|
-
|
|
1116
1016
|
fileprivate var waitingToPlayAnimation = false
|
|
1117
1017
|
|
|
1118
|
-
fileprivate var activeAnimationName: String {
|
|
1119
|
-
switch animationLayer?.primaryAnimationKey {
|
|
1120
|
-
case .specific(let animationKey):
|
|
1121
|
-
return animationKey
|
|
1122
|
-
case .managed, nil:
|
|
1123
|
-
return _activeAnimationName
|
|
1124
|
-
}
|
|
1125
|
-
}
|
|
1126
|
-
|
|
1127
|
-
fileprivate func makeAnimationLayer(usingEngine renderingEngine: RenderingEngineOption) {
|
|
1128
|
-
/// Remove current animation if any
|
|
1129
|
-
removeCurrentAnimation()
|
|
1130
|
-
|
|
1131
|
-
if let oldAnimation = animationLayer {
|
|
1132
|
-
oldAnimation.removeFromSuperlayer()
|
|
1133
|
-
animationLayer = nil
|
|
1134
|
-
}
|
|
1135
|
-
|
|
1136
|
-
invalidateIntrinsicContentSize()
|
|
1137
|
-
|
|
1138
|
-
guard let animation = animation else {
|
|
1139
|
-
return
|
|
1140
|
-
}
|
|
1141
|
-
|
|
1142
|
-
let rootAnimationLayer: RootAnimationLayer?
|
|
1143
|
-
switch renderingEngine {
|
|
1144
|
-
case .automatic:
|
|
1145
|
-
rootAnimationLayer = makeAutomaticEngineLayer(for: animation)
|
|
1146
|
-
case .specific(.coreAnimation):
|
|
1147
|
-
rootAnimationLayer = makeCoreAnimationLayer(for: animation)
|
|
1148
|
-
case .specific(.mainThread):
|
|
1149
|
-
rootAnimationLayer = makeMainThreadAnimationLayer(for: animation)
|
|
1150
|
-
}
|
|
1151
|
-
|
|
1152
|
-
guard let animationLayer = rootAnimationLayer else {
|
|
1153
|
-
return
|
|
1154
|
-
}
|
|
1155
|
-
|
|
1156
|
-
animationLayer.animationView = self
|
|
1157
|
-
animationLayer.renderScale = screenScale
|
|
1158
|
-
|
|
1159
|
-
viewLayer?.addSublayer(animationLayer)
|
|
1160
|
-
self.animationLayer = animationLayer
|
|
1161
|
-
reloadImages()
|
|
1162
|
-
animationLayer.setNeedsDisplay()
|
|
1163
|
-
setNeedsLayout()
|
|
1164
|
-
currentFrame = CGFloat(animation.startFrame)
|
|
1165
|
-
}
|
|
1166
|
-
|
|
1167
|
-
fileprivate func makeMainThreadAnimationLayer(for animation: LottieAnimation) -> MainThreadAnimationLayer {
|
|
1168
|
-
MainThreadAnimationLayer(
|
|
1169
|
-
animation: animation,
|
|
1170
|
-
imageProvider: imageProvider.cachedImageProvider,
|
|
1171
|
-
textProvider: textProvider,
|
|
1172
|
-
fontProvider: fontProvider,
|
|
1173
|
-
maskAnimationToBounds: maskAnimationToBounds,
|
|
1174
|
-
logger: logger)
|
|
1175
|
-
}
|
|
1176
|
-
|
|
1177
|
-
fileprivate func makeCoreAnimationLayer(for animation: LottieAnimation) -> CoreAnimationLayer? {
|
|
1178
|
-
do {
|
|
1179
|
-
let coreAnimationLayer = try CoreAnimationLayer(
|
|
1180
|
-
animation: animation,
|
|
1181
|
-
imageProvider: imageProvider.cachedImageProvider,
|
|
1182
|
-
textProvider: textProvider,
|
|
1183
|
-
fontProvider: fontProvider,
|
|
1184
|
-
maskAnimationToBounds: maskAnimationToBounds,
|
|
1185
|
-
compatibilityTrackerMode: .track,
|
|
1186
|
-
logger: logger)
|
|
1187
|
-
|
|
1188
|
-
coreAnimationLayer.didSetUpAnimation = { [logger] compatibilityIssues in
|
|
1189
|
-
logger.assert(
|
|
1190
|
-
compatibilityIssues.isEmpty,
|
|
1191
|
-
"Encountered Core Animation compatibility issues while setting up animation:\n"
|
|
1192
|
-
+ compatibilityIssues.map { $0.description }.joined(separator: "\n") + "\n\n"
|
|
1193
|
-
+ """
|
|
1194
|
-
This animation cannot be rendered correctly by the Core Animation engine.
|
|
1195
|
-
To resolve this issue, you can use `RenderingEngineOption.automatic`, which automatically falls back
|
|
1196
|
-
to the Main Thread rendering engine when necessary, or just use `RenderingEngineOption.mainThread`.
|
|
1197
|
-
|
|
1198
|
-
""")
|
|
1199
|
-
}
|
|
1200
|
-
|
|
1201
|
-
return coreAnimationLayer
|
|
1202
|
-
} catch {
|
|
1203
|
-
// This should never happen, because we initialize the `CoreAnimationLayer` with
|
|
1204
|
-
// `CompatibilityTracker.Mode.track` (which reports errors in `didSetUpAnimation`,
|
|
1205
|
-
// not by throwing).
|
|
1206
|
-
logger.assertionFailure("Encountered unexpected error \(error)")
|
|
1207
|
-
return nil
|
|
1208
|
-
}
|
|
1209
|
-
}
|
|
1210
|
-
|
|
1211
|
-
fileprivate func makeAutomaticEngineLayer(for animation: LottieAnimation) -> CoreAnimationLayer? {
|
|
1212
|
-
do {
|
|
1213
|
-
// Attempt to set up the Core Animation layer. This can either throw immediately in `init`,
|
|
1214
|
-
// or throw an error later in `CALayer.display()` that will be reported in `didSetUpAnimation`.
|
|
1215
|
-
let coreAnimationLayer = try CoreAnimationLayer(
|
|
1216
|
-
animation: animation,
|
|
1217
|
-
imageProvider: imageProvider.cachedImageProvider,
|
|
1218
|
-
textProvider: textProvider,
|
|
1219
|
-
fontProvider: fontProvider,
|
|
1220
|
-
maskAnimationToBounds: maskAnimationToBounds,
|
|
1221
|
-
compatibilityTrackerMode: .abort,
|
|
1222
|
-
logger: logger)
|
|
1223
|
-
|
|
1224
|
-
coreAnimationLayer.didSetUpAnimation = { [weak self] issues in
|
|
1225
|
-
self?.automaticEngineLayerDidSetUpAnimation(issues)
|
|
1226
|
-
}
|
|
1227
|
-
|
|
1228
|
-
return coreAnimationLayer
|
|
1229
|
-
} catch {
|
|
1230
|
-
if case CompatibilityTracker.Error.encounteredCompatibilityIssue(let compatibilityIssue) = error {
|
|
1231
|
-
automaticEngineLayerDidSetUpAnimation([compatibilityIssue])
|
|
1232
|
-
} else {
|
|
1233
|
-
// This should never happen, because we expect `CoreAnimationLayer` to only throw
|
|
1234
|
-
// `CompatibilityTracker.Error.encounteredCompatibilityIssue` errors.
|
|
1235
|
-
logger.assertionFailure("Encountered unexpected error \(error)")
|
|
1236
|
-
automaticEngineLayerDidSetUpAnimation([])
|
|
1237
|
-
}
|
|
1238
|
-
|
|
1239
|
-
return nil
|
|
1240
|
-
}
|
|
1241
|
-
}
|
|
1242
|
-
|
|
1243
|
-
// Handles any compatibility issues with the Core Animation engine
|
|
1244
|
-
// by falling back to the Main Thread engine
|
|
1245
|
-
fileprivate func automaticEngineLayerDidSetUpAnimation(_ compatibilityIssues: [CompatibilityIssue]) {
|
|
1246
|
-
// If there weren't any compatibility issues, then there's nothing else to do
|
|
1247
|
-
if compatibilityIssues.isEmpty {
|
|
1248
|
-
return
|
|
1249
|
-
}
|
|
1250
|
-
|
|
1251
|
-
logger.warn(
|
|
1252
|
-
"Encountered Core Animation compatibility issue while setting up animation:\n"
|
|
1253
|
-
+ compatibilityIssues.map { $0.description }.joined(separator: "\n") + "\n"
|
|
1254
|
-
+ """
|
|
1255
|
-
This animation may have additional compatibility issues, but animation setup was cancelled early to avoid wasted work.
|
|
1256
|
-
|
|
1257
|
-
Automatically falling back to Main Thread rendering engine. This fallback comes with some additional performance
|
|
1258
|
-
overhead, which can be reduced by manually specifying that this animation should always use the Main Thread engine.
|
|
1259
|
-
|
|
1260
|
-
""")
|
|
1261
|
-
|
|
1262
|
-
let animationContext = animationContext
|
|
1263
|
-
let currentFrame = currentFrame
|
|
1264
|
-
|
|
1265
|
-
// Disable the completion handler delegate before tearing down the `CoreAnimationLayer`
|
|
1266
|
-
// and building the `MainThreadAnimationLayer`. Otherwise deinitializing the
|
|
1267
|
-
// `CoreAnimationLayer` would trigger the animation completion handler even though
|
|
1268
|
-
// the animation hasn't even started playing yet.
|
|
1269
|
-
animationContext?.closure.ignoreDelegate = true
|
|
1270
|
-
|
|
1271
|
-
makeAnimationLayer(usingEngine: .mainThread)
|
|
1272
|
-
|
|
1273
|
-
// Set up the Main Thread animation layer using the same configuration that
|
|
1274
|
-
// was being used by the previous Core Animation layer
|
|
1275
|
-
self.currentFrame = currentFrame
|
|
1276
|
-
|
|
1277
|
-
if let animationContext = animationContext {
|
|
1278
|
-
// `AnimationContext.closure` (`AnimationCompletionDelegate`) is a reference type
|
|
1279
|
-
// that is the animation layer's `CAAnimationDelegate`, and holds a reference to
|
|
1280
|
-
// the animation layer. Reusing a single instance across different animation layers
|
|
1281
|
-
// can cause the animation setup to fail, so we create a copy of the `animationContext`:
|
|
1282
|
-
addNewAnimationForContext(AnimationContext(
|
|
1283
|
-
playFrom: animationContext.playFrom,
|
|
1284
|
-
playTo: animationContext.playTo,
|
|
1285
|
-
closure: animationContext.closure.completionBlock))
|
|
1286
|
-
}
|
|
1287
|
-
}
|
|
1288
|
-
|
|
1289
1018
|
fileprivate func updateAnimationForBackgroundState() {
|
|
1290
|
-
|
|
1291
|
-
switch backgroundBehavior {
|
|
1292
|
-
case .stop:
|
|
1293
|
-
removeCurrentAnimation()
|
|
1294
|
-
updateAnimationFrame(currentContext.playFrom)
|
|
1295
|
-
case .pause:
|
|
1296
|
-
removeCurrentAnimation()
|
|
1297
|
-
case .pauseAndRestore:
|
|
1298
|
-
currentContext.closure.ignoreDelegate = true
|
|
1299
|
-
removeCurrentAnimation()
|
|
1300
|
-
/// Keep the stale context around for when the app enters the foreground.
|
|
1301
|
-
animationContext = currentContext
|
|
1302
|
-
case .forceFinish:
|
|
1303
|
-
removeCurrentAnimation()
|
|
1304
|
-
updateAnimationFrame(currentContext.playTo)
|
|
1305
|
-
case .continuePlaying:
|
|
1306
|
-
break
|
|
1307
|
-
}
|
|
1308
|
-
}
|
|
1019
|
+
lottieAnimationLayer.updateAnimationForBackgroundState()
|
|
1309
1020
|
}
|
|
1310
1021
|
|
|
1311
1022
|
fileprivate func updateAnimationForForegroundState() {
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
addNewAnimationForContext(currentContext)
|
|
1316
|
-
} else if backgroundBehavior == .pauseAndRestore {
|
|
1317
|
-
/// Restore animation from saved state
|
|
1318
|
-
updateInFlightAnimation()
|
|
1319
|
-
}
|
|
1023
|
+
let wasWaitingToPlayAnimation = waitingToPlayAnimation
|
|
1024
|
+
if waitingToPlayAnimation {
|
|
1025
|
+
waitingToPlayAnimation = false
|
|
1320
1026
|
}
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
/// Removes the current animation and pauses the animation at the current frame
|
|
1324
|
-
/// if necessary before setting up a new animation.
|
|
1325
|
-
/// - This is not necessary with the Core Animation engine, and skipping
|
|
1326
|
-
/// this step lets us avoid building the animations twice (once paused
|
|
1327
|
-
/// and once again playing)
|
|
1328
|
-
/// - This method should only be called immediately before setting up another
|
|
1329
|
-
/// animation -- otherwise this LottieAnimationView could be put in an inconsistent state.
|
|
1330
|
-
fileprivate func removeCurrentAnimationIfNecessary() {
|
|
1331
|
-
switch currentRenderingEngine {
|
|
1332
|
-
case .mainThread:
|
|
1333
|
-
removeCurrentAnimation()
|
|
1334
|
-
case .coreAnimation, nil:
|
|
1335
|
-
// We still need to remove the `animationContext`, since it should only be present
|
|
1336
|
-
// when an animation is actually playing. Without this calling `removeCurrentAnimationIfNecessary()`
|
|
1337
|
-
// and then setting the animation to a specific paused frame would put this
|
|
1338
|
-
// `LottieAnimationView` in an inconsistent state.
|
|
1339
|
-
animationContext = nil
|
|
1340
|
-
}
|
|
1341
|
-
}
|
|
1342
|
-
|
|
1343
|
-
/// Stops the current in flight animation and freezes the animation in its current state.
|
|
1344
|
-
fileprivate func removeCurrentAnimation() {
|
|
1345
|
-
guard animationContext != nil else { return }
|
|
1346
|
-
let pauseFrame = realtimeAnimationFrame
|
|
1347
|
-
animationLayer?.removeAnimation(forKey: activeAnimationName)
|
|
1348
|
-
updateAnimationFrame(pauseFrame)
|
|
1349
|
-
animationContext = nil
|
|
1350
|
-
}
|
|
1351
|
-
|
|
1352
|
-
/// Adds animation to animation layer and sets the delegate. If animation layer or animation are nil, exits.
|
|
1353
|
-
fileprivate func addNewAnimationForContext(_ animationContext: AnimationContext) {
|
|
1354
|
-
guard let animationlayer = animationLayer, let animation = animation else {
|
|
1355
|
-
return
|
|
1356
|
-
}
|
|
1357
|
-
|
|
1358
|
-
self.animationContext = animationContext
|
|
1359
|
-
|
|
1360
|
-
switch currentRenderingEngine {
|
|
1361
|
-
case .mainThread:
|
|
1362
|
-
guard window != nil else {
|
|
1363
|
-
waitingToPlayAnimation = true
|
|
1364
|
-
return
|
|
1365
|
-
}
|
|
1366
|
-
|
|
1367
|
-
case .coreAnimation, nil:
|
|
1368
|
-
// The Core Animation engine automatically batches animation setup to happen
|
|
1369
|
-
// in `CALayer.display()`, which won't be called until the layer is on-screen,
|
|
1370
|
-
// so we don't need to defer animation setup at this layer.
|
|
1371
|
-
break
|
|
1372
|
-
}
|
|
1373
|
-
|
|
1374
|
-
animationID = animationID + 1
|
|
1375
|
-
_activeAnimationName = LottieAnimationView.animationName + String(animationID)
|
|
1376
|
-
|
|
1377
|
-
if let coreAnimationLayer = animationlayer as? CoreAnimationLayer {
|
|
1378
|
-
var animationContext = animationContext
|
|
1379
|
-
|
|
1380
|
-
// Core Animation doesn't natively support negative speed values,
|
|
1381
|
-
// so instead we can swap `playFrom` / `playTo`
|
|
1382
|
-
if animationSpeed < 0 {
|
|
1383
|
-
let temp = animationContext.playFrom
|
|
1384
|
-
animationContext.playFrom = animationContext.playTo
|
|
1385
|
-
animationContext.playTo = temp
|
|
1386
|
-
}
|
|
1387
|
-
|
|
1388
|
-
var timingConfiguration = CoreAnimationLayer.CAMediaTimingConfiguration(
|
|
1389
|
-
autoreverses: loopMode.caAnimationConfiguration.autoreverses,
|
|
1390
|
-
repeatCount: loopMode.caAnimationConfiguration.repeatCount,
|
|
1391
|
-
speed: abs(Float(animationSpeed)))
|
|
1392
|
-
|
|
1393
|
-
// The animation should start playing from the `currentFrame`,
|
|
1394
|
-
// if `currentFrame` is included in the time range being played.
|
|
1395
|
-
let lowerBoundTime = min(animationContext.playFrom, animationContext.playTo)
|
|
1396
|
-
let upperBoundTime = max(animationContext.playFrom, animationContext.playTo)
|
|
1397
|
-
if (lowerBoundTime ..< upperBoundTime).contains(round(currentFrame)) {
|
|
1398
|
-
// We have to configure this differently depending on the loop mode:
|
|
1399
|
-
switch loopMode {
|
|
1400
|
-
// When playing exactly once (and not looping), we can just set the
|
|
1401
|
-
// `playFrom` time to be the `currentFrame`. Since the animation duration
|
|
1402
|
-
// is based on `playFrom` and `playTo`, this automatically truncates the
|
|
1403
|
-
// duration (so the animation stops playing at `playFrom`).
|
|
1404
|
-
// - Don't do this if the animation is already at that frame
|
|
1405
|
-
// (e.g. playing from 100% to 0% when the animation is already at 0%)
|
|
1406
|
-
// since that would cause the animation to not play at all.
|
|
1407
|
-
case .playOnce:
|
|
1408
|
-
if animationContext.playTo != currentFrame {
|
|
1409
|
-
animationContext.playFrom = currentFrame
|
|
1410
|
-
}
|
|
1411
|
-
|
|
1412
|
-
// When looping, we specifically _don't_ want to affect the duration of the animation,
|
|
1413
|
-
// since that would affect the duration of all subsequent loops. We just want to adjust
|
|
1414
|
-
// the duration of the _first_ loop. Instead of setting `playFrom`, we just add a `timeOffset`
|
|
1415
|
-
// so the first loop begins at `currentTime` but all subsequent loops are the standard duration.
|
|
1416
|
-
default:
|
|
1417
|
-
if animationSpeed < 0 {
|
|
1418
|
-
timingConfiguration.timeOffset = animation.time(forFrame: animationContext.playFrom) - currentTime
|
|
1419
|
-
} else {
|
|
1420
|
-
timingConfiguration.timeOffset = currentTime - animation.time(forFrame: animationContext.playFrom)
|
|
1421
|
-
}
|
|
1422
|
-
}
|
|
1423
|
-
}
|
|
1424
|
-
|
|
1425
|
-
// If attempting to play a zero-duration animation, just pause on that single frame instead
|
|
1426
|
-
if animationContext.playFrom == animationContext.playTo {
|
|
1427
|
-
currentFrame = animationContext.playTo
|
|
1428
|
-
animationContext.closure.completionBlock?(true)
|
|
1429
|
-
return
|
|
1430
|
-
}
|
|
1431
|
-
|
|
1432
|
-
coreAnimationLayer.playAnimation(configuration: .init(
|
|
1433
|
-
animationContext: animationContext,
|
|
1434
|
-
timingConfiguration: timingConfiguration))
|
|
1435
|
-
|
|
1436
|
-
return
|
|
1437
|
-
}
|
|
1438
|
-
|
|
1439
|
-
/// At this point there is no animation on animationLayer and its state is set.
|
|
1440
|
-
|
|
1441
|
-
let framerate = animation.framerate
|
|
1442
|
-
|
|
1443
|
-
let playFrom = animationContext.playFrom.clamp(animation.startFrame, animation.endFrame)
|
|
1444
|
-
let playTo = animationContext.playTo.clamp(animation.startFrame, animation.endFrame)
|
|
1445
|
-
|
|
1446
|
-
let duration = ((max(playFrom, playTo) - min(playFrom, playTo)) / CGFloat(framerate))
|
|
1447
|
-
|
|
1448
|
-
let playingForward: Bool =
|
|
1449
|
-
(
|
|
1450
|
-
(animationSpeed > 0 && playFrom < playTo) ||
|
|
1451
|
-
(animationSpeed < 0 && playTo < playFrom))
|
|
1452
|
-
|
|
1453
|
-
var startFrame = currentFrame.clamp(min(playFrom, playTo), max(playFrom, playTo))
|
|
1454
|
-
if startFrame == playTo {
|
|
1455
|
-
startFrame = playFrom
|
|
1456
|
-
}
|
|
1457
|
-
|
|
1458
|
-
let timeOffset: TimeInterval = playingForward
|
|
1459
|
-
? Double(startFrame - min(playFrom, playTo)) / framerate
|
|
1460
|
-
: Double(max(playFrom, playTo) - startFrame) / framerate
|
|
1461
|
-
|
|
1462
|
-
let layerAnimation = CABasicAnimation(keyPath: "currentFrame")
|
|
1463
|
-
layerAnimation.fromValue = playFrom
|
|
1464
|
-
layerAnimation.toValue = playTo
|
|
1465
|
-
layerAnimation.speed = Float(animationSpeed)
|
|
1466
|
-
layerAnimation.duration = TimeInterval(duration)
|
|
1467
|
-
layerAnimation.fillMode = CAMediaTimingFillMode.both
|
|
1468
|
-
layerAnimation.repeatCount = loopMode.caAnimationConfiguration.repeatCount
|
|
1469
|
-
layerAnimation.autoreverses = loopMode.caAnimationConfiguration.autoreverses
|
|
1470
|
-
|
|
1471
|
-
layerAnimation.isRemovedOnCompletion = false
|
|
1472
|
-
if timeOffset != 0 {
|
|
1473
|
-
let currentLayerTime = viewLayer?.convertTime(CACurrentMediaTime(), from: nil) ?? 0
|
|
1474
|
-
layerAnimation.beginTime = currentLayerTime - (timeOffset * 1 / Double(abs(animationSpeed)))
|
|
1475
|
-
}
|
|
1476
|
-
layerAnimation.delegate = animationContext.closure
|
|
1477
|
-
animationContext.closure.animationLayer = animationlayer
|
|
1478
|
-
animationContext.closure.animationKey = activeAnimationName
|
|
1479
|
-
|
|
1480
|
-
animationlayer.add(layerAnimation, forKey: activeAnimationName)
|
|
1481
|
-
updateRasterizationState()
|
|
1027
|
+
lottieAnimationLayer.updateAnimationForForegroundState(wasWaitingToPlayAnimation: wasWaitingToPlayAnimation)
|
|
1482
1028
|
}
|
|
1483
1029
|
|
|
1484
1030
|
// MARK: Private
|
|
1485
1031
|
|
|
1486
|
-
|
|
1032
|
+
// The backing CALayer for this animation view.
|
|
1033
|
+
private let lottieAnimationLayer: LottieAnimationLayer
|
|
1487
1034
|
|
|
1488
1035
|
private let logger: LottieLogger
|
|
1489
|
-
|
|
1490
|
-
/// The `LottieBackgroundBehavior` that was specified manually by setting `self.backgroundBehavior`
|
|
1491
|
-
private var _backgroundBehavior: LottieBackgroundBehavior?
|
|
1492
|
-
|
|
1493
|
-
}
|
|
1494
|
-
|
|
1495
|
-
// MARK: - LottieLoopMode + caAnimationConfiguration
|
|
1496
|
-
|
|
1497
|
-
extension LottieLoopMode {
|
|
1498
|
-
/// The `CAAnimation` configuration that reflects this mode
|
|
1499
|
-
var caAnimationConfiguration: (repeatCount: Float, autoreverses: Bool) {
|
|
1500
|
-
switch self {
|
|
1501
|
-
case .playOnce:
|
|
1502
|
-
return (repeatCount: 1, autoreverses: false)
|
|
1503
|
-
case .loop:
|
|
1504
|
-
return (repeatCount: .greatestFiniteMagnitude, autoreverses: false)
|
|
1505
|
-
case .autoReverse:
|
|
1506
|
-
return (repeatCount: .greatestFiniteMagnitude, autoreverses: true)
|
|
1507
|
-
case .repeat(let amount):
|
|
1508
|
-
return (repeatCount: amount, autoreverses: false)
|
|
1509
|
-
case .repeatBackwards(let amount):
|
|
1510
|
-
return (repeatCount: amount, autoreverses: true)
|
|
1511
|
-
}
|
|
1512
|
-
}
|
|
1513
1036
|
}
|