lottie-ios 4.3.1 → 4.3.3

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
@@ -7,22 +7,22 @@
7
7
  <key>Lottie (iOS).xcscheme_^#shared#^_</key>
8
8
  <dict>
9
9
  <key>orderHint</key>
10
- <integer>2</integer>
10
+ <integer>3</integer>
11
11
  </dict>
12
12
  <key>Lottie (macOS).xcscheme_^#shared#^_</key>
13
13
  <dict>
14
14
  <key>orderHint</key>
15
- <integer>3</integer>
15
+ <integer>4</integer>
16
16
  </dict>
17
17
  <key>Lottie (tvOS).xcscheme_^#shared#^_</key>
18
18
  <dict>
19
19
  <key>orderHint</key>
20
- <integer>4</integer>
20
+ <integer>5</integer>
21
21
  </dict>
22
22
  <key>Lottie (visionOS).xcscheme_^#shared#^_</key>
23
23
  <dict>
24
24
  <key>orderHint</key>
25
- <integer>5</integer>
25
+ <integer>6</integer>
26
26
  </dict>
27
27
  </dict>
28
28
  <key>SuppressBuildableAutocreation</key>
@@ -302,6 +302,21 @@
302
302
  endingLineNumber = "412"
303
303
  offsetFromSymbolStart = "99">
304
304
  </Location>
305
+ <Location
306
+ uuid = "E5D4F221-8220-42A8-BB35-32D5BEE1328B - a6d45bb5484d1294"
307
+ shouldBeEnabled = "Yes"
308
+ ignoreCount = "0"
309
+ continueAfterRunningActions = "No"
310
+ symbolName = "__C.UIView.systemLayoutFittingIntrinsicWidthFixedHeight(_: CoreGraphics.CGFloat, priority: __C.UILayoutPriority) -&gt; __C.CGSize"
311
+ moduleName = "lottieBugReproduction"
312
+ usesParentBreakpointCondition = "Yes"
313
+ urlString = "file:///Users/calstephens/Documents/lottie/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/LayoutUtilities/SwiftUIMeasurementContainer.swift"
314
+ startingColumnNumber = "9223372036854775807"
315
+ endingColumnNumber = "9223372036854775807"
316
+ startingLineNumber = "412"
317
+ endingLineNumber = "412"
318
+ offsetFromSymbolStart = "99">
319
+ </Location>
305
320
  </Locations>
306
321
  </BreakpointContent>
307
322
  </BreakpointProxy>
@@ -426,6 +441,21 @@
426
441
  endingLineNumber = "393"
427
442
  offsetFromSymbolStart = "97">
428
443
  </Location>
444
+ <Location
445
+ uuid = "7043C7FC-0028-426B-91A7-E05945E62122 - 205d4f501848c002"
446
+ shouldBeEnabled = "Yes"
447
+ ignoreCount = "0"
448
+ continueAfterRunningActions = "No"
449
+ symbolName = "__C.UIView.systemLayoutFittingIntrinsicHeightFixedWidth(_: CoreGraphics.CGFloat, priority: __C.UILayoutPriority) -&gt; __C.CGSize"
450
+ moduleName = "lottieBugReproduction"
451
+ usesParentBreakpointCondition = "Yes"
452
+ urlString = "file:///Users/calstephens/Documents/lottie/Sources/Private/EmbeddedLibraries/EpoxyCore/SwiftUI/LayoutUtilities/SwiftUIMeasurementContainer.swift"
453
+ startingColumnNumber = "9223372036854775807"
454
+ endingColumnNumber = "9223372036854775807"
455
+ startingLineNumber = "393"
456
+ endingLineNumber = "393"
457
+ offsetFromSymbolStart = "97">
458
+ </Location>
429
459
  </Locations>
430
460
  </BreakpointContent>
431
461
  </BreakpointProxy>
@@ -566,6 +596,38 @@
566
596
  endingLineNumber = "40"
567
597
  landmarkName = "imageForAsset(asset:)"
568
598
  landmarkType = "7">
599
+ <Locations>
600
+ <Location
601
+ uuid = "6054DF71-1266-422E-9C2F-56F48E5C9F70 - e420b5ae81b770cf"
602
+ shouldBeEnabled = "Yes"
603
+ ignoreCount = "0"
604
+ continueAfterRunningActions = "No"
605
+ symbolName = "Lottie.FilepathImageProvider.imageForAsset(asset: Lottie.ImageAsset) -&gt; Swift.Optional&lt;__C.CGImageRef&gt;"
606
+ moduleName = "Lottie"
607
+ usesParentBreakpointCondition = "Yes"
608
+ urlString = "file:///Users/calstephens/Documents/lottie/Sources/Public/iOS/FilepathImageProvider.swift"
609
+ startingColumnNumber = "9223372036854775807"
610
+ endingColumnNumber = "9223372036854775807"
611
+ startingLineNumber = "40"
612
+ endingLineNumber = "40"
613
+ offsetFromSymbolStart = "724">
614
+ </Location>
615
+ <Location
616
+ uuid = "6054DF71-1266-422E-9C2F-56F48E5C9F70 - 505df6532c6b683a"
617
+ shouldBeEnabled = "Yes"
618
+ ignoreCount = "0"
619
+ continueAfterRunningActions = "No"
620
+ symbolName = "Lottie.FilepathImageProvider.imageForAsset(asset: Lottie.ImageAsset) -&gt; Swift.Optional&lt;__C.CGImageRef&gt;"
621
+ moduleName = "lottieBugReproduction"
622
+ usesParentBreakpointCondition = "Yes"
623
+ urlString = "file:///Users/calstephens/Documents/lottie/Sources/Public/iOS/FilepathImageProvider.swift"
624
+ startingColumnNumber = "9223372036854775807"
625
+ endingColumnNumber = "9223372036854775807"
626
+ startingLineNumber = "40"
627
+ endingLineNumber = "40"
628
+ offsetFromSymbolStart = "724">
629
+ </Location>
630
+ </Locations>
569
631
  </BreakpointContent>
570
632
  </BreakpointProxy>
571
633
  <BreakpointProxy
@@ -582,6 +644,53 @@
582
644
  endingLineNumber = "49"
583
645
  landmarkName = "reloadImages()"
584
646
  landmarkType = "7">
647
+ <Locations>
648
+ <Location
649
+ uuid = "8628051F-F131-475B-8FBA-5C9F7B7F9CF8 - b71115c8bcbe1c53"
650
+ shouldBeEnabled = "Yes"
651
+ ignoreCount = "0"
652
+ continueAfterRunningActions = "No"
653
+ symbolName = "Lottie.LayerImageProvider.reloadImages() -&gt; ()"
654
+ moduleName = "Lottie"
655
+ usesParentBreakpointCondition = "Yes"
656
+ urlString = "file:///Users/calstephens/Documents/lottie/Sources/Private/MainThread/LayerContainers/Utility/LayerImageProvider.swift"
657
+ startingColumnNumber = "9223372036854775807"
658
+ endingColumnNumber = "9223372036854775807"
659
+ startingLineNumber = "49"
660
+ endingLineNumber = "49"
661
+ offsetFromSymbolStart = "746">
662
+ </Location>
663
+ <Location
664
+ uuid = "8628051F-F131-475B-8FBA-5C9F7B7F9CF8 - 36c5635116204a6"
665
+ shouldBeEnabled = "Yes"
666
+ ignoreCount = "0"
667
+ continueAfterRunningActions = "No"
668
+ symbolName = "Lottie.LayerImageProvider.reloadImages() -&gt; ()"
669
+ moduleName = "lottieBugReproduction"
670
+ usesParentBreakpointCondition = "Yes"
671
+ urlString = "file:///Users/calstephens/Documents/lottie/Sources/Private/MainThread/LayerContainers/Utility/LayerImageProvider.swift"
672
+ startingColumnNumber = "9223372036854775807"
673
+ endingColumnNumber = "9223372036854775807"
674
+ startingLineNumber = "49"
675
+ endingLineNumber = "49"
676
+ offsetFromSymbolStart = "746">
677
+ </Location>
678
+ <Location
679
+ uuid = "8628051F-F131-475B-8FBA-5C9F7B7F9CF8 - 2d1ae2090cf799a0"
680
+ shouldBeEnabled = "Yes"
681
+ ignoreCount = "0"
682
+ continueAfterRunningActions = "No"
683
+ symbolName = "Lottie.LayerImageProvider.reloadImages() -&gt; ()"
684
+ moduleName = "Example (Multiplatform)"
685
+ usesParentBreakpointCondition = "Yes"
686
+ urlString = "file:///Users/calstephens/Documents/lottie/Sources/Private/MainThread/LayerContainers/Utility/LayerImageProvider.swift"
687
+ startingColumnNumber = "9223372036854775807"
688
+ endingColumnNumber = "9223372036854775807"
689
+ startingLineNumber = "49"
690
+ endingLineNumber = "49"
691
+ offsetFromSymbolStart = "746">
692
+ </Location>
693
+ </Locations>
585
694
  </BreakpointContent>
586
695
  </BreakpointProxy>
587
696
  </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.1")
44
+ .package(url: "https://github.com/airbnb/lottie-spm.git", from: "4.3.3")
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.
@@ -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)
385
430
 
386
- case .fromProgress(let fromProgress, let toProgress, let loopMode):
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)
439
+
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
@@ -1072,6 +1134,10 @@ public class LottieAnimationLayer: CALayer {
1072
1134
  }
1073
1135
 
1074
1136
  fileprivate func makeAnimationLayer(usingEngine renderingEngine: RenderingEngineOption) {
1137
+ /// Disable the default implicit crossfade animation Core Animation creates
1138
+ /// when adding or removing sublayers.
1139
+ actions = ["sublayers": NSNull()]
1140
+
1075
1141
  /// Remove current animation if any
1076
1142
  removeCurrentAnimation()
1077
1143
 
@@ -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
@@ -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
 
@@ -8,7 +8,7 @@
8
8
 
9
9
  Pod::Spec.new do |s|
10
10
  s.name = 'lottie-ios'
11
- s.version = '4.3.1'
11
+ s.version = '4.3.3'
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.1",
3
+ "version": "4.3.3",
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": {