lottie-ios 4.3.0 → 4.3.2

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.
@@ -32,30 +32,17 @@ jobs:
32
32
  xcode:
33
33
  - '14.2' # Swift 5.7
34
34
  - '14.3' # Swift 5.8
35
+ - '15.0' # Swift 5.9
35
36
  steps:
36
37
  - uses: actions/checkout@v2
37
38
  - uses: ./.github/actions/setup
38
39
  with:
39
40
  xcode: ${{ matrix.xcode }}
40
41
  - name: Build Package
42
+ # Once there is a production Xcode version with the visionOS SDK,
43
+ # we will want to use that version without `SKIP_VISION_OS=true`
41
44
  run: SKIP_VISION_OS=true bundle exec rake build:package:all
42
45
 
43
- build-package-macos-13-xcode-15:
44
- name: "Build Package"
45
- runs-on: macos-13
46
- strategy:
47
- fail-fast: false
48
- matrix:
49
- xcode:
50
- - '15.0' # Swift 5.9, first version that includes visionOS SDK.
51
- steps:
52
- - uses: actions/checkout@v2
53
- - uses: ./.github/actions/setup
54
- with:
55
- xcode: ${{ matrix.xcode }}
56
- - name: Build Package
57
- run: bundle exec rake build:package:all
58
-
59
46
  build-example:
60
47
  name: "Build Example App"
61
48
  runs-on: macos-13
@@ -65,7 +52,9 @@ jobs:
65
52
  with:
66
53
  xcode: '15.0' # Swift 5.9
67
54
  - name: Build Example
68
- run: bundle exec rake build:example:all
55
+ # Once there is a production Xcode version with the visionOS SDK,
56
+ # we will want to remove `SKIP_VISION_OS=true`
57
+ run: SKIP_VISION_OS=true bundle exec rake build:example:all
69
58
 
70
59
  test-package:
71
60
  name: "Test Package"
@@ -115,6 +104,8 @@ jobs:
115
104
  with:
116
105
  xcode: ${{ matrix.xcode }}
117
106
  - name: Build XCFramework
107
+ # Once there is a production Xcode version with the visionOS SDK, we will
108
+ # need to also build an XCFramework using that version but without `SKIP_VISION_OS=true`
118
109
  run: SKIP_VISION_OS=true bundle exec rake build:xcframework[Lottie-Xcode-${{ matrix.xcode }}]
119
110
  - name: Upload XCFramework
120
111
  uses: actions/upload-artifact@v2
@@ -128,32 +119,6 @@ jobs:
128
119
  # to an `archives` directory containing our `Lottie.xcframework.zip`.
129
120
  path: .build/archives
130
121
 
131
- build-xcframework-macos-13:
132
- name: "Build XCFramework"
133
- runs-on: macos-13
134
- strategy:
135
- matrix:
136
- xcode:
137
- - '15.0' # Swift 5.9, and the first Xcode version with the visionOS SDK.
138
- steps:
139
- - uses: actions/checkout@v2
140
- - uses: ./.github/actions/setup
141
- with:
142
- xcode: ${{ matrix.xcode }}
143
- - name: Build XCFramework
144
- run: bundle exec rake build:xcframework[Lottie-Xcode-${{ matrix.xcode }}]
145
- - name: Upload XCFramework
146
- uses: actions/upload-artifact@v2
147
- with:
148
- name: BuildProducts
149
- # The xcframework is at the path `.build/archives/Lottie.xcframework.zip`.
150
- # GitHub always zips the artifacts before uploading, so if we uploaded the .xframework.zip
151
- # directly then it would actually upload a double-zip (a .zip containing our `Lottie.xcframework.zip`).
152
- # This is confusing especially since macOS Archive Utility automatially unzips both layers at once.
153
- # Instead, we upload the entire archives folder, resulting in an `XCFramework.zip` that unzips
154
- # to an `archives` directory containing our `Lottie.xcframework.zip`.
155
- path: .build/archives
156
-
157
122
  cocoapod:
158
123
  name: "Lint CocoaPods podspec"
159
124
  runs-on: macos-13
@@ -171,7 +136,7 @@ jobs:
171
136
  strategy:
172
137
  matrix:
173
138
  xcode:
174
- - '15.0' # Swift 5.9, first version with visionOS SDK.
139
+ - '15.0' # Swift 5.9
175
140
  steps:
176
141
  - uses: actions/checkout@v2
177
142
  - uses: ./.github/actions/setup
@@ -330,6 +330,7 @@
330
330
  0887347B28F0CCDD00458627 /* LottieAnimationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0887347428F0CCDD00458627 /* LottieAnimationView.swift */; };
331
331
  0887347C28F0CCDD00458627 /* LottieAnimationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0887347428F0CCDD00458627 /* LottieAnimationView.swift */; };
332
332
  0887347D28F0CCDD00458627 /* LottieAnimationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0887347428F0CCDD00458627 /* LottieAnimationView.swift */; };
333
+ 089C50C22ABA0C6D007903D3 /* LoggingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 089C50C12ABA0C6D007903D3 /* LoggingTests.swift */; };
333
334
  08AB05552A61C20400DE86FD /* ReducedMotionOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08AB05542A61C20400DE86FD /* ReducedMotionOption.swift */; };
334
335
  08AB05562A61C20400DE86FD /* ReducedMotionOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08AB05542A61C20400DE86FD /* ReducedMotionOption.swift */; };
335
336
  08AB05572A61C20400DE86FD /* ReducedMotionOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08AB05542A61C20400DE86FD /* ReducedMotionOption.swift */; };
@@ -1176,6 +1177,7 @@
1176
1177
  0887347228F0CCDD00458627 /* LottieAnimationHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LottieAnimationHelpers.swift; sourceTree = "<group>"; };
1177
1178
  0887347328F0CCDD00458627 /* LottieAnimationViewInitializers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LottieAnimationViewInitializers.swift; sourceTree = "<group>"; };
1178
1179
  0887347428F0CCDD00458627 /* LottieAnimationView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LottieAnimationView.swift; sourceTree = "<group>"; };
1180
+ 089C50C12ABA0C6D007903D3 /* LoggingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggingTests.swift; sourceTree = "<group>"; };
1179
1181
  08AB05542A61C20400DE86FD /* ReducedMotionOption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReducedMotionOption.swift; sourceTree = "<group>"; };
1180
1182
  08AB05582A61C5B700DE86FD /* DecodingStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecodingStrategy.swift; sourceTree = "<group>"; };
1181
1183
  08AB055C2A61C5CC00DE86FD /* RenderingEngineOption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RenderingEngineOption.swift; sourceTree = "<group>"; };
@@ -1755,6 +1757,7 @@
1755
1757
  08CB2680291ED2B700B4F071 /* AnimationViewTests.swift */,
1756
1758
  2E70F79E295BB6D30089A0EF /* CompatibleAnimationViewTests.swift */,
1757
1759
  080F5FDB2AB1075000ADC32C /* TextProviderTests.swift */,
1760
+ 089C50C12ABA0C6D007903D3 /* LoggingTests.swift */,
1758
1761
  );
1759
1762
  path = Tests;
1760
1763
  sourceTree = "<group>";
@@ -3233,6 +3236,7 @@
3233
3236
  2EAF59A727A076BC00E00531 /* Bundle+Module.swift in Sources */,
3234
3237
  2E70F79F295BB6D30089A0EF /* CompatibleAnimationViewTests.swift in Sources */,
3235
3238
  2E8044AE27A07347006E74CB /* Snapshotting+presentationLayer.swift in Sources */,
3239
+ 089C50C22ABA0C6D007903D3 /* LoggingTests.swift in Sources */,
3236
3240
  36E57EAC28AF7ADF00B7EFDA /* HardcodedTextProvider.swift in Sources */,
3237
3241
  2E72128527BB32DB0027BC56 /* PerformanceTests.swift in Sources */,
3238
3242
  6DB3BDC328245AA2002A276D /* ParsingTests.swift in Sources */,
@@ -52,22 +52,6 @@
52
52
  </Locations>
53
53
  </BreakpointContent>
54
54
  </BreakpointProxy>
55
- <BreakpointProxy
56
- BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
57
- <BreakpointContent
58
- uuid = "7317D33F-83F7-487F-92D8-361AFDC3108F"
59
- shouldBeEnabled = "No"
60
- ignoreCount = "0"
61
- continueAfterRunningActions = "No"
62
- filePath = "Sources/Private/CoreAnimation/Layers/AnimationLayer.swift"
63
- startingColumnNumber = "9223372036854775807"
64
- endingColumnNumber = "9223372036854775807"
65
- startingLineNumber = "59"
66
- endingLineNumber = "59"
67
- landmarkName = "addingKeypathComponent(_:)"
68
- landmarkType = "7">
69
- </BreakpointContent>
70
- </BreakpointProxy>
71
55
  <BreakpointProxy
72
56
  BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
73
57
  <BreakpointContent
@@ -79,8 +63,8 @@
79
63
  filePath = "Sources/Private/CoreAnimation/Animations/CALayer+addAnimation.swift"
80
64
  startingColumnNumber = "9223372036854775807"
81
65
  endingColumnNumber = "9223372036854775807"
82
- startingLineNumber = "105"
83
- endingLineNumber = "105"
66
+ startingLineNumber = "104"
67
+ endingLineNumber = "104"
84
68
  landmarkName = "CALayer"
85
69
  landmarkType = "21">
86
70
  <Locations>
@@ -303,6 +287,21 @@
303
287
  endingLineNumber = "412"
304
288
  offsetFromSymbolStart = "127">
305
289
  </Location>
290
+ <Location
291
+ uuid = "E5D4F221-8220-42A8-BB35-32D5BEE1328B - 12a91848e5910a61"
292
+ shouldBeEnabled = "Yes"
293
+ ignoreCount = "0"
294
+ continueAfterRunningActions = "No"
295
+ symbolName = "__C.UIView.systemLayoutFittingIntrinsicWidthFixedHeight(_: CoreGraphics.CGFloat, priority: __C.UILayoutPriority) -&gt; __C.CGSize"
296
+ moduleName = "Lottie"
297
+ usesParentBreakpointCondition = "Yes"
298
+ urlString = "file:///Users/calstephens/Documents/lottie/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/LayoutUtilities/SwiftUIMeasurementContainer.swift"
299
+ startingColumnNumber = "9223372036854775807"
300
+ endingColumnNumber = "9223372036854775807"
301
+ startingLineNumber = "412"
302
+ endingLineNumber = "412"
303
+ offsetFromSymbolStart = "99">
304
+ </Location>
306
305
  </Locations>
307
306
  </BreakpointContent>
308
307
  </BreakpointProxy>
@@ -412,6 +411,21 @@
412
411
  endingLineNumber = "393"
413
412
  offsetFromSymbolStart = "128">
414
413
  </Location>
414
+ <Location
415
+ uuid = "7043C7FC-0028-426B-91A7-E05945E62122 - 94200cadb594d8f7"
416
+ shouldBeEnabled = "Yes"
417
+ ignoreCount = "0"
418
+ continueAfterRunningActions = "No"
419
+ symbolName = "__C.UIView.systemLayoutFittingIntrinsicHeightFixedWidth(_: CoreGraphics.CGFloat, priority: __C.UILayoutPriority) -&gt; __C.CGSize"
420
+ moduleName = "Lottie"
421
+ usesParentBreakpointCondition = "Yes"
422
+ urlString = "file:///Users/calstephens/Documents/lottie/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/LayoutUtilities/SwiftUIMeasurementContainer.swift"
423
+ startingColumnNumber = "9223372036854775807"
424
+ endingColumnNumber = "9223372036854775807"
425
+ startingLineNumber = "393"
426
+ endingLineNumber = "393"
427
+ offsetFromSymbolStart = "97">
428
+ </Location>
415
429
  </Locations>
416
430
  </BreakpointContent>
417
431
  </BreakpointProxy>
@@ -525,49 +539,49 @@
525
539
  <BreakpointProxy
526
540
  BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
527
541
  <BreakpointContent
528
- uuid = "75697A31-C456-456F-815B-95974E3598BE"
542
+ uuid = "93EDC5AB-8948-4148-83CC-FDDCB8BE5AFE"
529
543
  shouldBeEnabled = "No"
530
544
  ignoreCount = "0"
531
545
  continueAfterRunningActions = "No"
532
546
  filePath = "Example/Example/AnimationPreviewView.swift"
533
547
  startingColumnNumber = "9223372036854775807"
534
548
  endingColumnNumber = "9223372036854775807"
535
- startingLineNumber = "60"
536
- endingLineNumber = "60"
537
- landmarkName = "body"
538
- landmarkType = "24">
549
+ startingLineNumber = "119"
550
+ endingLineNumber = "119"
551
+ landmarkName = "AnimationPreviewView"
552
+ landmarkType = "14">
539
553
  </BreakpointContent>
540
554
  </BreakpointProxy>
541
555
  <BreakpointProxy
542
556
  BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
543
557
  <BreakpointContent
544
- uuid = "EAF29C5C-15A1-4F9D-AB63-8130DBD6049A"
558
+ uuid = "6054DF71-1266-422E-9C2F-56F48E5C9F70"
545
559
  shouldBeEnabled = "Yes"
546
560
  ignoreCount = "0"
547
561
  continueAfterRunningActions = "No"
548
- filePath = "Example/Example/AnimationPreviewView.swift"
562
+ filePath = "Sources/Public/iOS/FilepathImageProvider.swift"
549
563
  startingColumnNumber = "9223372036854775807"
550
564
  endingColumnNumber = "9223372036854775807"
551
- startingLineNumber = "59"
552
- endingLineNumber = "59"
553
- landmarkName = "body"
554
- landmarkType = "24">
565
+ startingLineNumber = "40"
566
+ endingLineNumber = "40"
567
+ landmarkName = "imageForAsset(asset:)"
568
+ landmarkType = "7">
555
569
  </BreakpointContent>
556
570
  </BreakpointProxy>
557
571
  <BreakpointProxy
558
572
  BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
559
573
  <BreakpointContent
560
- uuid = "93EDC5AB-8948-4148-83CC-FDDCB8BE5AFE"
561
- shouldBeEnabled = "No"
574
+ uuid = "8628051F-F131-475B-8FBA-5C9F7B7F9CF8"
575
+ shouldBeEnabled = "Yes"
562
576
  ignoreCount = "0"
563
577
  continueAfterRunningActions = "No"
564
- filePath = "Example/Example/AnimationPreviewView.swift"
578
+ filePath = "Sources/Private/MainThread/LayerContainers/Utility/LayerImageProvider.swift"
565
579
  startingColumnNumber = "9223372036854775807"
566
580
  endingColumnNumber = "9223372036854775807"
567
- startingLineNumber = "119"
568
- endingLineNumber = "119"
569
- landmarkName = "AnimationPreviewView"
570
- landmarkType = "14">
581
+ startingLineNumber = "49"
582
+ endingLineNumber = "49"
583
+ landmarkName = "reloadImages()"
584
+ landmarkType = "7">
571
585
  </BreakpointContent>
572
586
  </BreakpointProxy>
573
587
  </Breakpoints>
package/README.md CHANGED
@@ -41,7 +41,7 @@ To install Lottie using [Swift Package Manager](https://github.com/apple/swift-p
41
41
  or you can add the following dependency to your `Package.swift`:
42
42
 
43
43
  ```swift
44
- .package(url: "https://github.com/airbnb/lottie-spm.git", from: "4.3.0")
44
+ .package(url: "https://github.com/airbnb/lottie-spm.git", from: "4.3.2")
45
45
  ```
46
46
 
47
47
  When using Swift Package Manager we recommend using the [lottie-spm](https://github.com/airbnb/lottie-spm) repo instead of the main lottie-ios repo. The main git repository for [lottie-ios](https://github.com/airbnb/lottie-ios) is somewhat large (300+ MB), and Swift Package Manager always downloads the full repository with all git history. The [lottie-spm](https://github.com/airbnb/lottie-spm) repo is much smaller (less than 500kb), so can be downloaded much more quickly.
@@ -50,15 +50,14 @@ extension CALayer {
50
50
  guard !keyframes.isEmpty else { return nil }
51
51
 
52
52
  // Check if this set of keyframes uses After Effects expressions, which aren't supported.
53
- if let unsupportedAfterEffectsExpression = keyframeGroup.unsupportedAfterEffectsExpression {
53
+ // - We only log this once per `CoreAnimationLayer` instance.
54
+ if keyframeGroup.unsupportedAfterEffectsExpression != nil, !context.loggingState.hasLoggedAfterEffectsExpressionsWarning {
55
+ context.loggingState.hasLoggedAfterEffectsExpressionsWarning = true
54
56
  context.logger.info("""
55
57
  `\(property.caLayerKeypath)` animation for "\(context.currentKeypath.fullPath)" \
56
58
  includes an After Effects expression (https://helpx.adobe.com/after-effects/using/expression-language.html), \
57
59
  which is not supported by lottie-ios (expressions are only supported by lottie-web). \
58
60
  This animation may not play correctly.
59
-
60
- \(unsupportedAfterEffectsExpression.replacingOccurrences(of: "\n", with: "\n "))
61
-
62
61
  """)
63
62
  }
64
63
 
@@ -209,6 +209,7 @@ final class CoreAnimationLayer: BaseAnimationLayer {
209
209
  private let valueProviderStore: ValueProviderStore
210
210
  private let compatibilityTracker: CompatibilityTracker
211
211
  private let logger: LottieLogger
212
+ private let loggingState = LoggingState()
212
213
 
213
214
  /// The current playback state of the animation that is displayed in this layer
214
215
  private var currentPlaybackState: PlaybackState? {
@@ -265,6 +266,7 @@ final class CoreAnimationLayer: BaseAnimationLayer {
265
266
  valueProviderStore: valueProviderStore,
266
267
  compatibilityTracker: compatibilityTracker,
267
268
  logger: logger,
269
+ loggingState: loggingState,
268
270
  currentKeypath: AnimationKeypath(keys: []),
269
271
  textProvider: textProvider,
270
272
  recordHierarchyKeypath: configuration.recordHierarchyKeypath)
@@ -449,7 +451,9 @@ extension CoreAnimationLayer: RootAnimationLayer {
449
451
  }
450
452
 
451
453
  func forceDisplayUpdate() {
452
- display()
454
+ // Unimplemented
455
+ // - We can't call `display()` here, because it would cause unexpected frame animations:
456
+ // https://github.com/airbnb/lottie-ios/issues/2193
453
457
  }
454
458
 
455
459
  func logHierarchyKeypaths() {
@@ -38,6 +38,9 @@ struct LayerAnimationContext {
38
38
  /// The logger that should be used for assertions and warnings
39
39
  let logger: LottieLogger
40
40
 
41
+ /// Mutable state related to log events, stored on the `CoreAnimationLayer`.
42
+ let loggingState: LoggingState
43
+
41
44
  /// The AnimationKeypath represented by the current layer
42
45
  var currentKeypath: AnimationKeypath
43
46
 
@@ -84,3 +87,19 @@ struct LayerAnimationContext {
84
87
  return copy
85
88
  }
86
89
  }
90
+
91
+ // MARK: - LoggingState
92
+
93
+ /// Mutable state related to log events, stored on the `CoreAnimationLayer`.
94
+ final class LoggingState {
95
+
96
+ // MARK: Lifecycle
97
+
98
+ init() { }
99
+
100
+ // MARK: Internal
101
+
102
+ /// Whether or not the warning about unsupported After Effects expressions
103
+ /// has been logged yet for this layer.
104
+ var hasLoggedAfterEffectsExpressionsWarning = false
105
+ }
@@ -107,7 +107,7 @@ public class LottieAnimationLayer: CALayer {
107
107
  guard let animation = animation else { return }
108
108
 
109
109
  defer {
110
- currentPlaybackMode = .toProgress(1, loopMode: loopMode)
110
+ currentPlaybackMode = .playing(.fromProgress(nil, toProgress: 1, loopMode: loopMode))
111
111
  }
112
112
 
113
113
  if shouldOverrideWithReducedMotionAnimation {
@@ -139,7 +139,7 @@ public class LottieAnimationLayer: CALayer {
139
139
  guard let animation = animation else { return }
140
140
 
141
141
  defer {
142
- currentPlaybackMode = .fromProgress(fromProgress, toProgress: toProgress, loopMode: loopMode ?? self.loopMode)
142
+ currentPlaybackMode = .playing(.fromProgress(fromProgress, toProgress: toProgress, loopMode: loopMode ?? self.loopMode))
143
143
  }
144
144
 
145
145
  if shouldOverrideWithReducedMotionAnimation {
@@ -172,7 +172,7 @@ public class LottieAnimationLayer: CALayer {
172
172
  completion: LottieCompletionBlock? = nil)
173
173
  {
174
174
  defer {
175
- currentPlaybackMode = .fromFrame(fromFrame, toFrame: toFrame, loopMode: loopMode ?? self.loopMode)
175
+ currentPlaybackMode = .playing(.fromFrame(fromFrame, toFrame: toFrame, loopMode: loopMode ?? self.loopMode))
176
176
  }
177
177
 
178
178
  if shouldOverrideWithReducedMotionAnimation {
@@ -216,11 +216,11 @@ public class LottieAnimationLayer: CALayer {
216
216
  completion: LottieCompletionBlock? = nil)
217
217
  {
218
218
  defer {
219
- currentPlaybackMode = .fromMarker(
219
+ currentPlaybackMode = .playing(.fromMarker(
220
220
  fromMarker,
221
221
  toMarker: toMarker,
222
222
  playEndMarkerFrame: playEndMarkerFrame,
223
- loopMode: loopMode ?? self.loopMode)
223
+ loopMode: loopMode ?? self.loopMode))
224
224
  }
225
225
 
226
226
  if shouldOverrideWithReducedMotionAnimation {
@@ -273,7 +273,7 @@ public class LottieAnimationLayer: CALayer {
273
273
  }
274
274
 
275
275
  defer {
276
- currentPlaybackMode = .marker(marker, loopMode: loopMode ?? self.loopMode)
276
+ currentPlaybackMode = .playing(.marker(marker, loopMode: loopMode ?? self.loopMode))
277
277
  }
278
278
 
279
279
  if shouldOverrideWithReducedMotionAnimation {
@@ -311,7 +311,7 @@ public class LottieAnimationLayer: CALayer {
311
311
  guard !markers.isEmpty else { return }
312
312
 
313
313
  defer {
314
- currentPlaybackMode = .markers(markers)
314
+ currentPlaybackMode = .playing(.markers(markers))
315
315
  }
316
316
 
317
317
  if shouldOverrideWithReducedMotionAnimation {
@@ -357,62 +357,124 @@ public class LottieAnimationLayer: CALayer {
357
357
  ///
358
358
  /// The completion closure will be called with `false`
359
359
  open func pause() {
360
- removeCurrentAnimation()
361
- currentPlaybackMode = .pause
360
+ pause(at: .currentFrame)
362
361
  }
363
362
 
364
- /// Applies the given `LottiePlaybackMode` to this layer.
365
- /// - Parameter animationCompletionHandler: A closure that is called after
366
- /// an animation triggered by this method completes. This completion
367
- /// handler is **not called** after setting the playback mode to a
368
- /// mode that doesn't animate (e.g. `progress`, `frame`, `time`, or `pause`).
363
+ /// Pauses the animation at a given state.
364
+ open func pause(at state: LottiePlaybackMode.PausedState) {
365
+ switch state {
366
+ case .currentFrame:
367
+ removeCurrentAnimation()
368
+
369
+ case .progress(let animationProgressTime):
370
+ currentProgress = animationProgressTime
371
+
372
+ case .frame(let animationFrameTime):
373
+ currentFrame = animationFrameTime
374
+ case .time(let timeInterval):
375
+ currentTime = timeInterval
376
+
377
+ case .marker(let name, let position):
378
+ guard let from = animation?.markerMap?[name] else {
379
+ return
380
+ }
381
+
382
+ switch position {
383
+ case .start:
384
+ currentTime = from.frameTime
385
+ case .end:
386
+ currentTime = from.frameTime + from.durationFrameTime
387
+ }
388
+ }
389
+
390
+ currentPlaybackMode = .paused(at: state)
391
+ }
392
+
393
+ @available(*, deprecated, renamed: "setPlaybackMode(_:completion:)", message: "Will be removed in a future major release.")
369
394
  open func play(
370
395
  _ playbackMode: LottiePlaybackMode,
371
396
  animationCompletionHandler: LottieCompletionBlock? = nil)
397
+ {
398
+ setPlaybackMode(playbackMode, completion: animationCompletionHandler)
399
+ }
400
+
401
+ /// Applies the given `LottiePlaybackMode` to this layer.
402
+ /// - Parameter playbackMode: The playback mode to apply
403
+ /// - Parameter completion: A closure that is called after
404
+ /// an animation triggered by this method completes.
405
+ open func setPlaybackMode(
406
+ _ playbackMode: LottiePlaybackMode,
407
+ completion: LottieCompletionBlock? = nil)
372
408
  {
373
409
  switch playbackMode {
410
+ case .paused(at: let state):
411
+ pause(at: state)
412
+
413
+ case .playing(let mode):
414
+ play(mode, completion: completion)
415
+
374
416
  case .progress(let progress):
375
- currentProgress = progress
417
+ pause(at: .progress(progress))
376
418
 
377
419
  case .frame(let frame):
378
- currentFrame = frame
420
+ pause(at: .frame(frame))
379
421
 
380
422
  case .time(let time):
381
- currentTime = time
423
+ pause(at: .time(time))
382
424
 
383
425
  case .pause:
384
- pause()
426
+ pause(at: .currentFrame)
427
+
428
+ case .fromProgress(let from, let to, let loopMode):
429
+ play(.fromProgress(from, toProgress: to, loopMode: loopMode), completion: completion)
430
+
431
+ case .fromFrame(let from, let to, let loopMode):
432
+ play(.fromFrame(from, toFrame: to, loopMode: loopMode), completion: completion)
433
+
434
+ case .fromMarker(let from, let to, let playEndMarkerFrame, let loopMode):
435
+ play(.fromMarker(from, toMarker: to, playEndMarkerFrame: playEndMarkerFrame, loopMode: loopMode), completion: completion)
436
+
437
+ case .marker(let name, let loopMode):
438
+ play(.marker(name, loopMode: loopMode), completion: completion)
385
439
 
386
- case .fromProgress(let fromProgress, let toProgress, let loopMode):
440
+ case .markers(let names):
441
+ play(.markers(names), completion: completion)
442
+ }
443
+ }
444
+
445
+ /// Applies the given `LottiePlaybackMode` to this layer.
446
+ /// - Parameter playbackMode: The playback mode to apply
447
+ /// - Parameter completion: A closure that is called after
448
+ /// an animation triggered by this method completes.
449
+ open func play(_ playbackMode: LottiePlaybackMode.PlaybackMode, completion: LottieCompletionBlock? = nil) {
450
+ switch playbackMode {
451
+ case .fromProgress(let from, let to, let loopMode):
387
452
  play(
388
- fromProgress: fromProgress,
389
- toProgress: toProgress,
453
+ fromProgress: from,
454
+ toProgress: to,
390
455
  loopMode: loopMode,
391
- completion: animationCompletionHandler)
456
+ completion: completion)
392
457
 
393
- case .fromFrame(let fromFrame, let toFrame, let loopMode):
458
+ case .fromFrame(let from, let to, let loopMode):
394
459
  play(
395
- fromFrame: fromFrame,
396
- toFrame: toFrame,
460
+ fromFrame: from,
461
+ toFrame: to,
397
462
  loopMode: loopMode,
398
- completion: animationCompletionHandler)
463
+ completion: completion)
399
464
 
400
- case .fromMarker(let fromMarker, let toMarker, let playEndMarkerFrame, let loopMode):
465
+ case .fromMarker(let from, let to, let playEndMarkerFrame, let loopMode):
401
466
  play(
402
- fromMarker: fromMarker,
403
- toMarker: toMarker,
467
+ fromMarker: from,
468
+ toMarker: to,
404
469
  playEndMarkerFrame: playEndMarkerFrame,
405
470
  loopMode: loopMode,
406
- completion: animationCompletionHandler)
471
+ completion: completion)
407
472
 
408
- case .marker(let marker, let loopMode):
409
- play(
410
- marker: marker,
411
- loopMode: loopMode,
412
- completion: animationCompletionHandler)
473
+ case .marker(let name, loopMode: let loopMode):
474
+ play(marker: name, loopMode: loopMode, completion: completion)
413
475
 
414
- case .markers(let markers):
415
- play(markers: markers, completion: animationCompletionHandler)
476
+ case .markers(let names):
477
+ play(markers: names, completion: completion)
416
478
  }
417
479
  }
418
480
 
@@ -602,7 +664,7 @@ public class LottieAnimationLayer: CALayer {
602
664
  set {
603
665
  if let animation = animation {
604
666
  currentFrame = animation.frameTime(forProgress: newValue)
605
- currentPlaybackMode = .progress(newValue)
667
+ currentPlaybackMode = .paused(at: .progress(newValue))
606
668
  } else {
607
669
  currentFrame = 0
608
670
  }
@@ -624,7 +686,7 @@ public class LottieAnimationLayer: CALayer {
624
686
  set {
625
687
  if let animation = animation {
626
688
  currentFrame = animation.frameTime(forTime: newValue)
627
- currentPlaybackMode = .time(newValue)
689
+ currentPlaybackMode = .paused(at: .time(newValue))
628
690
  } else {
629
691
  currentFrame = 0
630
692
  }
@@ -645,7 +707,7 @@ public class LottieAnimationLayer: CALayer {
645
707
  set {
646
708
  removeCurrentAnimationIfNecessary()
647
709
  updateAnimationFrame(newValue)
648
- currentPlaybackMode = .frame(currentFrame)
710
+ currentPlaybackMode = .paused(at: .frame(currentFrame))
649
711
  }
650
712
  get {
651
713
  rootAnimationLayer?.currentFrame ?? 0
@@ -219,6 +219,13 @@ open class LottieAnimationView: LottieAnimationViewBase {
219
219
 
220
220
  // MARK: Open
221
221
 
222
+ /// Applies the given `LottiePlaybackMode` to this layer.
223
+ /// - Parameter completion: A closure that is called after
224
+ /// an animation triggered by this method completes.
225
+ open func play(_ mode: LottiePlaybackMode.PlaybackMode, completion: LottieCompletionBlock? = nil) {
226
+ lottieAnimationLayer.play(mode, completion: completion)
227
+ }
228
+
222
229
  /// Plays the animation from its current state to the end.
223
230
  ///
224
231
  /// - Parameter completion: An optional completion closure to be called when the animation completes playing.
@@ -341,16 +348,22 @@ open class LottieAnimationView: LottieAnimationViewBase {
341
348
  lottieAnimationLayer.pause()
342
349
  }
343
350
 
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`).
351
+ @available(*, deprecated, renamed: "setPlaybackMode(_:completion:)", message: "Will be removed in a future major release.")
349
352
  open func play(
350
353
  _ playbackMode: LottiePlaybackMode,
351
354
  animationCompletionHandler: LottieCompletionBlock? = nil)
352
355
  {
353
- lottieAnimationLayer.play(playbackMode, animationCompletionHandler: animationCompletionHandler)
356
+ lottieAnimationLayer.setPlaybackMode(playbackMode, completion: animationCompletionHandler)
357
+ }
358
+
359
+ /// Applies the given `LottiePlaybackMode` to this layer.
360
+ /// - Parameter completion: A closure that is called after
361
+ /// an animation triggered by this method completes.
362
+ open func setPlaybackMode(
363
+ _ playbackMode: LottiePlaybackMode,
364
+ completion: LottieCompletionBlock? = nil)
365
+ {
366
+ lottieAnimationLayer.setPlaybackMode(playbackMode, completion: completion)
354
367
  }
355
368
 
356
369
  // MARK: Public
@@ -794,6 +807,9 @@ open class LottieAnimationView: LottieAnimationViewBase {
794
807
 
795
808
  // MARK: Internal
796
809
 
810
+ // The backing CALayer for this animation view.
811
+ let lottieAnimationLayer: LottieAnimationLayer
812
+
797
813
  var animationLayer: RootAnimationLayer? {
798
814
  lottieAnimationLayer.rootAnimationLayer
799
815
  }
@@ -1029,8 +1045,5 @@ open class LottieAnimationView: LottieAnimationViewBase {
1029
1045
 
1030
1046
  // MARK: Private
1031
1047
 
1032
- // The backing CALayer for this animation view.
1033
- private let lottieAnimationLayer: LottieAnimationLayer
1034
-
1035
1048
  private let logger: LottieLogger
1036
1049
  }
@@ -7,91 +7,173 @@ import Foundation
7
7
 
8
8
  /// Configuration for how a Lottie animation should be played
9
9
  public enum LottiePlaybackMode: Hashable {
10
- /// The animation is paused at the given progress value,
11
- /// a value between 0.0 (0% progress) and 1.0 (100% progress).
10
+
11
+ /// The animation is paused at the given state (e.g. paused at a specific frame)
12
+ case paused(at: PausedState)
13
+
14
+ /// The animation is playing using the given playback mode (e.g. looping from the start to the end)
15
+ case playing(_ mode: PlaybackMode)
16
+
17
+ @available(*, deprecated, renamed: "LottiePlaybackMode.paused(at:)", message: "Will be removed in a future major release.")
12
18
  case progress(_ progress: AnimationProgressTime)
13
19
 
14
- /// The animation is paused at the given frame of the animation.
20
+ @available(*, deprecated, renamed: "LottiePlaybackMode.paused(at:)", message: "Will be removed in a future major release.")
15
21
  case frame(_ frame: AnimationFrameTime)
16
22
 
17
- /// The animation is paused at the given time value from the start of the animation.
23
+ @available(*, deprecated, renamed: "LottiePlaybackMode.paused(at:)", message: "Will be removed in a future major release.")
18
24
  case time(_ time: TimeInterval)
19
25
 
20
- /// Any existing animation will be paused at the current frame.
26
+ @available(*, deprecated, renamed: "LottiePlaybackMode.paused(at:)", message: "Will be removed in a future major release.")
21
27
  case pause
22
28
 
23
- /// Plays the animation from a progress (0-1) to a progress (0-1).
24
- /// - Parameter fromProgress: The start progress of the animation. If `nil` the animation will start at the current progress.
25
- /// - Parameter toProgress: The end progress of the animation.
26
- /// - Parameter loopMode: The loop behavior of the animation.
29
+ @available(*, deprecated, renamed: "LottiePlaybackMode.playing(_:)", message: "Will be removed in a future major release.")
27
30
  case fromProgress(_ fromProgress: AnimationProgressTime?, toProgress: AnimationProgressTime, loopMode: LottieLoopMode)
28
31
 
29
- /// The animation plays from the given `fromFrame` to the given `toFrame`.
30
- /// - Parameter fromFrame: The start frame of the animation. If `nil` the animation will start at the current frame.
31
- /// - Parameter toFrame: The end frame of the animation.
32
- /// - Parameter loopMode: The loop behavior of the animation.
32
+ @available(*, deprecated, renamed: "LottiePlaybackMode.playing(_:)", message: "Will be removed in a future major release.")
33
33
  case fromFrame(_ fromFrame: AnimationFrameTime?, toFrame: AnimationFrameTime, loopMode: LottieLoopMode)
34
34
 
35
- /// Plays the animation from a named marker to another marker.
36
- ///
37
- /// Markers are point in time that are encoded into the Animation data and assigned a name.
38
- ///
39
- /// NOTE: If markers are not found the play command will exit.
40
- ///
41
- /// - Parameter fromMarker: The start marker for the animation playback. If `nil` the
42
- /// animation will start at the current progress.
43
- /// - Parameter toMarker: The end marker for the animation playback.
44
- /// - Parameter playEndMarkerFrame: A flag to determine whether or not to play the frame of the end marker. If the
45
- /// end marker represents the end of the section to play, it should be to true. If the provided end marker
46
- /// represents the beginning of the next section, it should be false.
47
- /// - Parameter loopMode: The loop behavior of the animation.
35
+ @available(*, deprecated, renamed: "LottiePlaybackMode.playing(_:)", message: "Will be removed in a future major release.")
48
36
  case fromMarker(
49
37
  _ fromMarker: String?,
50
38
  toMarker: String,
51
39
  playEndMarkerFrame: Bool = true,
52
40
  loopMode: LottieLoopMode)
53
41
 
54
- /// Plays the animation from a named marker to the end of the marker's duration.
55
- ///
56
- /// A marker is a point in time with an associated duration that is encoded into the
57
- /// animation data and assigned a name.
58
- ///
59
- /// NOTE: If marker is not found the play command will exit.
60
- ///
61
- /// - Parameter marker: The start marker for the animation playback.
62
- /// - Parameter loopMode: The loop behavior of the animation.
42
+ @available(*, deprecated, renamed: "LottiePlaybackMode.playing(_:)", message: "Will be removed in a future major release.")
63
43
  case marker(_ marker: String, loopMode: LottieLoopMode)
64
44
 
65
- /// Plays the given markers sequentially in order.
66
- ///
67
- /// A marker is a point in time with an associated duration that is encoded into the
68
- /// animation data and assigned a name. Multiple markers can be played sequentially
69
- /// to create programmable animations.
70
- ///
71
- /// If a marker is not found, it will be skipped.
72
- ///
73
- /// If a marker doesn't have a duration value, it will play with a duration of 0
74
- /// (effectively being skipped).
75
- ///
76
- /// If another animation is played (by calling any `play` method) while this
77
- /// marker sequence is playing, the marker sequence will be cancelled.
78
- ///
79
- /// - Parameter markers: The list of markers to play sequentially.
45
+ @available(*, deprecated, renamed: "LottiePlaybackMode.playing(_:)", message: "Will be removed in a future major release.")
80
46
  case markers(_ markers: [String])
47
+
48
+ // MARK: Public
49
+
50
+ public enum PausedState: Hashable {
51
+ /// Any existing animation will be paused at the current frame.
52
+ case currentFrame
53
+
54
+ /// The animation is paused at the given progress value,
55
+ /// a value between 0.0 (0% progress) and 1.0 (100% progress).
56
+ case progress(_ progress: AnimationProgressTime)
57
+
58
+ /// The animation is paused at the given frame of the animation.
59
+ case frame(_ frame: AnimationFrameTime)
60
+
61
+ /// The animation is paused at the given time value from the start of the animation.
62
+ case time(_ time: TimeInterval)
63
+
64
+ /// Pauses the animation at a given marker and position
65
+ case marker(_ name: String, position: LottieMarkerPosition = .start)
66
+ }
67
+
68
+ public enum PlaybackMode: Hashable {
69
+ /// Plays the animation from a progress (0-1) to a progress (0-1).
70
+ /// - Parameter fromProgress: The start progress of the animation. If `nil` the animation will start at the current progress.
71
+ /// - Parameter toProgress: The end progress of the animation.
72
+ /// - Parameter loopMode: The loop behavior of the animation.
73
+ case fromProgress(
74
+ _ fromProgress: AnimationProgressTime?,
75
+ toProgress: AnimationProgressTime,
76
+ loopMode: LottieLoopMode)
77
+
78
+ /// The animation plays from the given `fromFrame` to the given `toFrame`.
79
+ /// - Parameter fromFrame: The start frame of the animation. If `nil` the animation will start at the current frame.
80
+ /// - Parameter toFrame: The end frame of the animation.
81
+ /// - Parameter loopMode: The loop behavior of the animation.
82
+ case fromFrame(
83
+ _ fromFrame: AnimationFrameTime?,
84
+ toFrame: AnimationFrameTime,
85
+ loopMode: LottieLoopMode)
86
+
87
+ /// Plays the animation from a named marker to another marker.
88
+ ///
89
+ /// Markers are point in time that are encoded into the Animation data and assigned a name.
90
+ ///
91
+ /// NOTE: If markers are not found the play command will exit.
92
+ ///
93
+ /// - Parameter fromMarker: The start marker for the animation playback. If `nil` the
94
+ /// animation will start at the current progress.
95
+ /// - Parameter toMarker: The end marker for the animation playback.
96
+ /// - Parameter playEndMarkerFrame: A flag to determine whether or not to play the frame of the end marker. If the
97
+ /// end marker represents the end of the section to play, it should be to true. If the provided end marker
98
+ /// represents the beginning of the next section, it should be false.
99
+ /// - Parameter loopMode: The loop behavior of the animation.
100
+ case fromMarker(
101
+ _ fromMarker: String?,
102
+ toMarker: String,
103
+ playEndMarkerFrame: Bool = true,
104
+ loopMode: LottieLoopMode)
105
+
106
+ /// Plays the animation from a named marker to the end of the marker's duration.
107
+ ///
108
+ /// A marker is a point in time with an associated duration that is encoded into the
109
+ /// animation data and assigned a name.
110
+ ///
111
+ /// NOTE: If marker is not found the play command will exit.
112
+ ///
113
+ /// - Parameter marker: The start marker for the animation playback.
114
+ /// - Parameter loopMode: The loop behavior of the animation.
115
+ case marker(
116
+ _ marker: String,
117
+ loopMode: LottieLoopMode)
118
+
119
+ /// Plays the given markers sequentially in order.
120
+ ///
121
+ /// A marker is a point in time with an associated duration that is encoded into the
122
+ /// animation data and assigned a name. Multiple markers can be played sequentially
123
+ /// to create programmable animations.
124
+ ///
125
+ /// If a marker is not found, it will be skipped.
126
+ ///
127
+ /// If a marker doesn't have a duration value, it will play with a duration of 0
128
+ /// (effectively being skipped).
129
+ ///
130
+ /// If another animation is played (by calling any `play` method) while this
131
+ /// marker sequence is playing, the marker sequence will be cancelled.
132
+ ///
133
+ /// - Parameter markers: The list of markers to play sequentially.
134
+ case markers(_ markers: [String])
135
+ }
136
+
81
137
  }
82
138
 
83
139
  extension LottiePlaybackMode {
140
+ public static var paused: Self {
141
+ .paused(at: .currentFrame)
142
+ }
143
+
144
+ @available(*, deprecated, renamed: "LottiePlaybackMode.playing(_:)", message: "Will be removed in a future major release.")
145
+ public static func toProgress(_ toProgress: AnimationProgressTime, loopMode: LottieLoopMode) -> LottiePlaybackMode {
146
+ .playing(.fromProgress(nil, toProgress: toProgress, loopMode: loopMode))
147
+ }
148
+
149
+ @available(*, deprecated, renamed: "LottiePlaybackMode.playing(_:)", message: "Will be removed in a future major release.")
150
+ public static func toFrame(_ toFrame: AnimationFrameTime, loopMode: LottieLoopMode) -> LottiePlaybackMode {
151
+ .playing(.fromFrame(nil, toFrame: toFrame, loopMode: loopMode))
152
+ }
153
+
154
+ @available(*, deprecated, renamed: "LottiePlaybackMode.playing(_:)", message: "Will be removed in a future major release.")
155
+ public static func toMarker(
156
+ _ toMarker: String,
157
+ playEndMarkerFrame: Bool = true,
158
+ loopMode: LottieLoopMode)
159
+ -> LottiePlaybackMode
160
+ {
161
+ .playing(.fromMarker(nil, toMarker: toMarker, playEndMarkerFrame: playEndMarkerFrame, loopMode: loopMode))
162
+ }
163
+ }
164
+
165
+ extension LottiePlaybackMode.PlaybackMode {
84
166
  /// Plays the animation from the current progress to a progress value (0-1).
85
167
  /// - Parameter toProgress: The end progress of the animation.
86
168
  /// - Parameter loopMode: The loop behavior of the animation.
87
- public static func toProgress(_ toProgress: AnimationProgressTime, loopMode: LottieLoopMode) -> LottiePlaybackMode {
169
+ public static func toProgress(_ toProgress: AnimationProgressTime, loopMode: LottieLoopMode) -> Self {
88
170
  .fromProgress(nil, toProgress: toProgress, loopMode: loopMode)
89
171
  }
90
172
 
91
173
  // Plays the animation from the current frame to the given frame.
92
174
  /// - Parameter toFrame: The end frame of the animation.
93
175
  /// - Parameter loopMode: The loop behavior of the animation.
94
- public static func toFrame(_ toFrame: AnimationFrameTime, loopMode: LottieLoopMode) -> LottiePlaybackMode {
176
+ public static func toFrame(_ toFrame: AnimationFrameTime, loopMode: LottieLoopMode) -> Self {
95
177
  .fromFrame(nil, toFrame: toFrame, loopMode: loopMode)
96
178
  }
97
179
 
@@ -110,8 +192,16 @@ extension LottiePlaybackMode {
110
192
  _ toMarker: String,
111
193
  playEndMarkerFrame: Bool = true,
112
194
  loopMode: LottieLoopMode)
113
- -> LottiePlaybackMode
195
+ -> Self
114
196
  {
115
197
  .fromMarker(nil, toMarker: toMarker, playEndMarkerFrame: playEndMarkerFrame, loopMode: loopMode)
116
198
  }
117
199
  }
200
+
201
+ // MARK: - LottieMarkerPosition
202
+
203
+ /// The position within a marker.
204
+ public enum LottieMarkerPosition: Hashable {
205
+ case start
206
+ case end
207
+ }
@@ -140,7 +140,7 @@ public struct LottieView<Placeholder: View>: UIViewConfiguringSwiftUIView {
140
140
  let playbackMode = playbackMode,
141
141
  playbackMode != context.view.currentPlaybackMode
142
142
  {
143
- context.view.play(playbackMode, animationCompletionHandler: animationCompletionHandler)
143
+ context.view.setPlaybackMode(playbackMode, completion: animationCompletionHandler)
144
144
  }
145
145
  }
146
146
  .configurations(configurations)
@@ -175,27 +175,47 @@ public struct LottieView<Placeholder: View>: UIViewConfiguringSwiftUIView {
175
175
  return copy
176
176
  }
177
177
 
178
- // Returns a copy of this view playing once from the current frame to the end frame
178
+ @available(*, deprecated, renamed: "playing()", message: "Will be removed in a future major release.")
179
179
  public func play() -> Self {
180
- play(loopMode: .playOnce)
180
+ playbackMode(.playing(.fromProgress(nil, toProgress: 1, loopMode: .playOnce)))
181
181
  }
182
182
 
183
183
  /// Returns a copy of this view that loops its animation from the start to end whenever visible
184
184
  public func looping() -> Self {
185
- play(.fromProgress(0, toProgress: 1, loopMode: .loop))
185
+ playbackMode(.playing(.fromProgress(0, toProgress: 1, loopMode: .loop)))
186
186
  }
187
187
 
188
- /// Returns a copy of this view playing from the current frame to the end frame,
189
- /// with the given `LottiePlaybackMode`.
188
+ @available(*, deprecated, renamed: "playing(_:)", message: "Will be removed in a future major release.")
190
189
  public func play(loopMode: LottieLoopMode = .playOnce) -> Self {
191
- play(.toProgress(1, loopMode: loopMode))
190
+ playbackMode(.playing(.fromProgress(nil, toProgress: 1, loopMode: loopMode)))
192
191
  }
193
192
 
194
- /// Returns a copy of this view playing with the given `LottiePlaybackMode`
193
+ @available(*, deprecated, renamed: "playbackMode(_:)", message: "Will be removed in a future major release.")
195
194
  public func play(_ playbackMode: LottiePlaybackMode) -> Self {
196
195
  self.playbackMode(playbackMode)
197
196
  }
198
197
 
198
+ /// Returns a copy of this view playing with the given playback mode
199
+ public func playing(_ mode: LottiePlaybackMode.PlaybackMode) -> Self {
200
+ playbackMode(.playing(mode))
201
+ }
202
+
203
+ /// Returns a copy of this view playing from the current frame to the end frame,
204
+ /// with the given `LottiePlaybackMode`.
205
+ public func playing(loopMode: LottieLoopMode) -> Self {
206
+ playbackMode(.playing(.fromProgress(nil, toProgress: 1, loopMode: loopMode)))
207
+ }
208
+
209
+ // Returns a copy of this view playing once from the current frame to the end frame
210
+ public func playing() -> Self {
211
+ playbackMode(.playing(.fromProgress(nil, toProgress: 1, loopMode: .playOnce)))
212
+ }
213
+
214
+ /// Returns a copy of this view paused with the given state
215
+ public func paused(at state: LottiePlaybackMode.PausedState = .currentFrame) -> Self {
216
+ playbackMode(.paused(at: state))
217
+ }
218
+
199
219
  /// Returns a copy of this view using the given `LottiePlaybackMode`
200
220
  public func playbackMode(_ playbackMode: LottiePlaybackMode) -> Self {
201
221
  var copy = self
@@ -332,7 +352,7 @@ public struct LottieView<Placeholder: View>: UIViewConfiguringSwiftUIView {
332
352
  public func currentProgress(_ currentProgress: AnimationProgressTime?) -> Self {
333
353
  guard let currentProgress = currentProgress else { return self }
334
354
  var copy = self
335
- copy.playbackMode = .progress(currentProgress)
355
+ copy.playbackMode = .paused(at: .progress(currentProgress))
336
356
  return copy
337
357
  }
338
358
 
@@ -344,7 +364,7 @@ public struct LottieView<Placeholder: View>: UIViewConfiguringSwiftUIView {
344
364
  public func currentFrame(_ currentFrame: AnimationFrameTime?) -> Self {
345
365
  guard let currentFrame = currentFrame else { return self }
346
366
  var copy = self
347
- copy.playbackMode = .frame(currentFrame)
367
+ copy.playbackMode = .paused(at: .frame(currentFrame))
348
368
  return copy
349
369
  }
350
370
 
@@ -356,7 +376,7 @@ public struct LottieView<Placeholder: View>: UIViewConfiguringSwiftUIView {
356
376
  public func currentTime(_ currentTime: TimeInterval?) -> Self {
357
377
  guard let currentTime = currentTime else { return self }
358
378
  var copy = self
359
- copy.playbackMode = .time(currentTime)
379
+ copy.playbackMode = .paused(at: .time(currentTime))
360
380
  return copy
361
381
  }
362
382
 
@@ -193,8 +193,10 @@ public final class CompatibleAnimationView: UIView {
193
193
  commonInit()
194
194
  }
195
195
 
196
- required init?(coder _: NSCoder) {
197
- fatalError("init(coder:) has not been implemented")
196
+ required init?(coder: NSCoder) {
197
+ animationView = LottieAnimationView()
198
+ super.init(coder: coder)
199
+ commonInit()
198
200
  }
199
201
 
200
202
  // MARK: Public
@@ -8,7 +8,7 @@
8
8
 
9
9
  Pod::Spec.new do |s|
10
10
  s.name = 'lottie-ios'
11
- s.version = '4.3.0'
11
+ s.version = '4.3.2'
12
12
  s.summary = 'A library to render native animations from bodymovin json'
13
13
 
14
14
  s.description = <<-DESC
@@ -22,7 +22,7 @@ Lottie enables designers to create and ship beautiful animations without an engi
22
22
  s.author = { 'Brandon Withrow' => 'buba447@gmail.com', 'Cal Stephens' => 'cal.stephens@airbnb.com' }
23
23
  s.source = { :git => 'https://github.com/airbnb/lottie-ios.git', :tag => s.version.to_s }
24
24
 
25
- s.swift_version = '5.5'
25
+ s.swift_version = '5.6'
26
26
  s.ios.deployment_target = '11.0'
27
27
  s.osx.deployment_target = '10.12'
28
28
  s.tvos.deployment_target = '11.0'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lottie-ios",
3
- "version": "4.3.0",
3
+ "version": "4.3.2",
4
4
  "description": "Lottie is a mobile library for Android and iOS that parses Adobe After Effects animations exported as json with bodymovin and renders the vector animations natively on mobile and through React Native!",
5
5
  "main": "index.js",
6
6
  "scripts": {