lottie-ios 4.1.2 → 4.1.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.
Files changed (26) hide show
  1. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  2. package/README.md +3 -3
  3. package/Rakefile +5 -1
  4. package/Sources/Private/CoreAnimation/Animations/LayerProperty.swift +9 -2
  5. package/Sources/Private/CoreAnimation/Animations/TransformAnimations.swift +58 -9
  6. package/Sources/Private/CoreAnimation/Extensions/Keyframes+combined.swift +16 -12
  7. package/Sources/Private/CoreAnimation/Layers/BaseCompositionLayer.swift +19 -4
  8. package/Sources/Private/CoreAnimation/Layers/ImageLayer.swift +2 -2
  9. package/Sources/Private/CoreAnimation/Layers/PreCompLayer.swift +1 -1
  10. package/Sources/Private/CoreAnimation/Layers/RepeaterLayer.swift +13 -2
  11. package/Sources/Private/MainThread/LayerContainers/Utility/LayerTransformNode.swift +13 -4
  12. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderContainers/GroupNode.swift +17 -5
  13. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/Text/TextAnimatorNode.swift +25 -6
  14. package/Sources/Private/Model/Objects/Transform.swift +58 -17
  15. package/Sources/Private/Model/ShapeItems/Repeater.swift +41 -7
  16. package/Sources/Private/Model/ShapeItems/ShapeTransform.swift +61 -7
  17. package/Sources/Private/Model/Text/TextAnimator.swift +37 -5
  18. package/Sources/Private/Utility/Primitives/ColorExtension.swift +10 -13
  19. package/Sources/Private/Utility/Primitives/VectorsExtensions.swift +28 -6
  20. package/Sources/Public/Animation/LottieAnimationView.swift +161 -159
  21. package/Sources/Public/DotLottie/DotLottieFileHelpers.swift +9 -3
  22. package/Sources/Public/iOS/Compatibility/CompatibleAnimationView.swift +32 -0
  23. package/Sources/Public/iOS/LottieAnimationViewBase.swift +1 -1
  24. package/Sources/Public/macOS/LottieAnimationViewBase.macOS.swift +1 -1
  25. package/lottie-ios.podspec +1 -1
  26. package/package.json +1 -1
@@ -22,8 +22,19 @@ final class Repeater: ShapeItem {
22
22
  .decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .startOpacity) ?? KeyframeGroup(LottieVector1D(100))
23
23
  endOpacity = try transformContainer
24
24
  .decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .endOpacity) ?? KeyframeGroup(LottieVector1D(100))
25
- rotation = try transformContainer
26
- .decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotation) ?? KeyframeGroup(LottieVector1D(0))
25
+ if let rotation = try transformContainer.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotation) {
26
+ rotationZ = rotation
27
+ } else if let rotation = try transformContainer.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotationZ) {
28
+ rotationZ = rotation
29
+ } else {
30
+ rotationZ = KeyframeGroup(LottieVector1D(0))
31
+ }
32
+
33
+ rotationX = try transformContainer
34
+ .decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotationX) ?? KeyframeGroup(LottieVector1D(0))
35
+ rotationY = try transformContainer
36
+ .decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotationY) ?? KeyframeGroup(LottieVector1D(0))
37
+
27
38
  position = try transformContainer
28
39
  .decodeIfPresent(KeyframeGroup<LottieVector3D>.self, forKey: .position) ??
29
40
  KeyframeGroup(LottieVector3D(x: Double(0), y: 0, z: 0))
@@ -58,10 +69,22 @@ final class Repeater: ShapeItem {
58
69
  } else {
59
70
  endOpacity = KeyframeGroup(LottieVector1D(100))
60
71
  }
72
+ if let rotationDictionary = transformDictionary[TransformKeys.rotationX.rawValue] as? [String: Any] {
73
+ rotationX = try KeyframeGroup<LottieVector1D>(dictionary: rotationDictionary)
74
+ } else {
75
+ rotationX = KeyframeGroup(LottieVector1D(0))
76
+ }
77
+ if let rotationDictionary = transformDictionary[TransformKeys.rotationY.rawValue] as? [String: Any] {
78
+ rotationY = try KeyframeGroup<LottieVector1D>(dictionary: rotationDictionary)
79
+ } else {
80
+ rotationY = KeyframeGroup(LottieVector1D(0))
81
+ }
61
82
  if let rotationDictionary = transformDictionary[TransformKeys.rotation.rawValue] as? [String: Any] {
62
- rotation = try KeyframeGroup<LottieVector1D>(dictionary: rotationDictionary)
83
+ rotationZ = try KeyframeGroup<LottieVector1D>(dictionary: rotationDictionary)
84
+ } else if let rotationDictionary = transformDictionary[TransformKeys.rotationZ.rawValue] as? [String: Any] {
85
+ rotationZ = try KeyframeGroup<LottieVector1D>(dictionary: rotationDictionary)
63
86
  } else {
64
- rotation = KeyframeGroup(LottieVector1D(0))
87
+ rotationZ = KeyframeGroup(LottieVector1D(0))
65
88
  }
66
89
  if let positionDictionary = transformDictionary[TransformKeys.position.rawValue] as? [String: Any] {
67
90
  position = try KeyframeGroup<LottieVector3D>(dictionary: positionDictionary)
@@ -95,8 +118,14 @@ final class Repeater: ShapeItem {
95
118
  /// End opacity
96
119
  let endOpacity: KeyframeGroup<LottieVector1D>
97
120
 
98
- /// The rotation
99
- let rotation: KeyframeGroup<LottieVector1D>
121
+ /// The rotation on X axis
122
+ let rotationX: KeyframeGroup<LottieVector1D>
123
+
124
+ /// The rotation on Y axis
125
+ let rotationY: KeyframeGroup<LottieVector1D>
126
+
127
+ /// The rotation on Z axis
128
+ let rotationZ: KeyframeGroup<LottieVector1D>
100
129
 
101
130
  /// Anchor Point
102
131
  let anchorPoint: KeyframeGroup<LottieVector3D>
@@ -115,7 +144,9 @@ final class Repeater: ShapeItem {
115
144
  var transformContainer = container.nestedContainer(keyedBy: TransformKeys.self, forKey: .transform)
116
145
  try transformContainer.encode(startOpacity, forKey: .startOpacity)
117
146
  try transformContainer.encode(endOpacity, forKey: .endOpacity)
118
- try transformContainer.encode(rotation, forKey: .rotation)
147
+ try transformContainer.encode(rotationX, forKey: .rotationX)
148
+ try transformContainer.encode(rotationY, forKey: .rotationY)
149
+ try transformContainer.encode(rotationZ, forKey: .rotationZ)
119
150
  try transformContainer.encode(position, forKey: .position)
120
151
  try transformContainer.encode(anchorPoint, forKey: .anchorPoint)
121
152
  try transformContainer.encode(scale, forKey: .scale)
@@ -131,6 +162,9 @@ final class Repeater: ShapeItem {
131
162
 
132
163
  private enum TransformKeys: String, CodingKey {
133
164
  case rotation = "r"
165
+ case rotationX = "rx"
166
+ case rotationY = "ry"
167
+ case rotationZ = "rz"
134
168
  case startOpacity = "so"
135
169
  case endOpacity = "eo"
136
170
  case anchorPoint = "a"
@@ -22,8 +22,25 @@ final class ShapeTransform: ShapeItem {
22
22
  scale = try container
23
23
  .decodeIfPresent(KeyframeGroup<LottieVector3D>.self, forKey: .scale) ??
24
24
  KeyframeGroup(LottieVector3D(x: Double(100), y: 100, z: 100))
25
- rotation = try container
26
- .decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotation) ?? KeyframeGroup(LottieVector1D(0))
25
+
26
+ rotationX = try container
27
+ .decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotationX) ?? KeyframeGroup(LottieVector1D(0))
28
+ rotationY = try container
29
+ .decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotationY) ?? KeyframeGroup(LottieVector1D(0))
30
+ if
31
+ let rotation = try container
32
+ .decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotation)
33
+ {
34
+ rotationZ = rotation
35
+ } else if
36
+ let rotation = try container
37
+ .decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotationZ)
38
+ {
39
+ rotationZ = rotation
40
+ } else {
41
+ rotationZ = KeyframeGroup(LottieVector1D(0))
42
+ }
43
+
27
44
  opacity = try container
28
45
  .decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .opacity) ?? KeyframeGroup(LottieVector1D(100))
29
46
  skew = try container.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .skew) ?? KeyframeGroup(LottieVector1D(0))
@@ -57,14 +74,39 @@ final class ShapeTransform: ShapeItem {
57
74
  } else {
58
75
  scale = KeyframeGroup(LottieVector3D(x: Double(100), y: 100, z: 100))
59
76
  }
77
+
78
+ if
79
+ let rotationDictionary = dictionary[CodingKeys.rotationX.rawValue] as? [String: Any],
80
+ let rotation = try? KeyframeGroup<LottieVector1D>(dictionary: rotationDictionary)
81
+ {
82
+ rotationX = rotation
83
+ } else {
84
+ rotationX = KeyframeGroup(LottieVector1D(0))
85
+ }
86
+
87
+ if
88
+ let rotationDictionary = dictionary[CodingKeys.rotationY.rawValue] as? [String: Any],
89
+ let rotation = try? KeyframeGroup<LottieVector1D>(dictionary: rotationDictionary)
90
+ {
91
+ rotationY = rotation
92
+ } else {
93
+ rotationY = KeyframeGroup(LottieVector1D(0))
94
+ }
95
+
60
96
  if
61
97
  let rotationDictionary = dictionary[CodingKeys.rotation.rawValue] as? [String: Any],
62
98
  let rotation = try? KeyframeGroup<LottieVector1D>(dictionary: rotationDictionary)
63
99
  {
64
- self.rotation = rotation
100
+ rotationZ = rotation
101
+ } else if
102
+ let rotationDictionary = dictionary[CodingKeys.rotationZ.rawValue] as? [String: Any],
103
+ let rotation = try? KeyframeGroup<LottieVector1D>(dictionary: rotationDictionary)
104
+ {
105
+ rotationZ = rotation
65
106
  } else {
66
- rotation = KeyframeGroup(LottieVector1D(0))
107
+ rotationZ = KeyframeGroup(LottieVector1D(0))
67
108
  }
109
+
68
110
  if
69
111
  let opacityDictionary = dictionary[CodingKeys.opacity.rawValue] as? [String: Any],
70
112
  let opacity = try? KeyframeGroup<LottieVector1D>(dictionary: opacityDictionary)
@@ -89,6 +131,7 @@ final class ShapeTransform: ShapeItem {
89
131
  } else {
90
132
  skewAxis = KeyframeGroup(LottieVector1D(0))
91
133
  }
134
+
92
135
  try super.init(dictionary: dictionary)
93
136
  }
94
137
 
@@ -103,8 +146,14 @@ final class ShapeTransform: ShapeItem {
103
146
  /// Scale
104
147
  let scale: KeyframeGroup<LottieVector3D>
105
148
 
106
- /// Rotation
107
- let rotation: KeyframeGroup<LottieVector1D>
149
+ /// Rotation on X axis
150
+ let rotationX: KeyframeGroup<LottieVector1D>
151
+
152
+ /// Rotation on Y axis
153
+ let rotationY: KeyframeGroup<LottieVector1D>
154
+
155
+ /// Rotation on Z axis
156
+ let rotationZ: KeyframeGroup<LottieVector1D>
108
157
 
109
158
  /// opacity
110
159
  let opacity: KeyframeGroup<LottieVector1D>
@@ -130,7 +179,9 @@ final class ShapeTransform: ShapeItem {
130
179
  try container.encode(anchor, forKey: .anchor)
131
180
  try container.encode(position, forKey: .position)
132
181
  try container.encode(scale, forKey: .scale)
133
- try container.encode(rotation, forKey: .rotation)
182
+ try container.encode(rotationX, forKey: .rotationX)
183
+ try container.encode(rotationY, forKey: .rotationY)
184
+ try container.encode(rotationZ, forKey: .rotationZ)
134
185
  try container.encode(opacity, forKey: .opacity)
135
186
  try container.encode(skew, forKey: .skew)
136
187
  try container.encode(skewAxis, forKey: .skewAxis)
@@ -143,6 +194,9 @@ final class ShapeTransform: ShapeItem {
143
194
  case position = "p"
144
195
  case scale = "s"
145
196
  case rotation = "r"
197
+ case rotationX = "rx"
198
+ case rotationY = "ry"
199
+ case rotationZ = "rz"
146
200
  case opacity = "o"
147
201
  case skew = "sk"
148
202
  case skewAxis = "sa"
@@ -24,7 +24,15 @@ final class TextAnimator: Codable, DictionaryInitializable {
24
24
  scale = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieVector3D>.self, forKey: .scale)
25
25
  skew = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .skew)
26
26
  skewAxis = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .skewAxis)
27
- rotation = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotation)
27
+ rotationX = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotationX)
28
+ rotationY = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotationY)
29
+ if let rotation = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotation) {
30
+ rotationZ = rotation
31
+ } else if let rotation = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .rotationZ) {
32
+ rotationZ = rotation
33
+ } else {
34
+ rotationZ = nil
35
+ }
28
36
  opacity = try animatorContainer.decodeIfPresent(KeyframeGroup<LottieVector1D>.self, forKey: .opacity)
29
37
  }
30
38
 
@@ -76,11 +84,26 @@ final class TextAnimator: Codable, DictionaryInitializable {
76
84
  } else {
77
85
  skewAxis = nil
78
86
  }
87
+ if let rotationDictionary = animatorDictionary[TextAnimatorKeys.rotationX.rawValue] as? [String: Any] {
88
+ rotationX = try? KeyframeGroup<LottieVector1D>(dictionary: rotationDictionary)
89
+ } else {
90
+ rotationX = nil
91
+ }
92
+
93
+ if let rotationDictionary = animatorDictionary[TextAnimatorKeys.rotationY.rawValue] as? [String: Any] {
94
+ rotationY = try? KeyframeGroup<LottieVector1D>(dictionary: rotationDictionary)
95
+ } else {
96
+ rotationY = nil
97
+ }
98
+
79
99
  if let rotationDictionary = animatorDictionary[TextAnimatorKeys.rotation.rawValue] as? [String: Any] {
80
- rotation = try? KeyframeGroup<LottieVector1D>(dictionary: rotationDictionary)
100
+ rotationZ = try? KeyframeGroup<LottieVector1D>(dictionary: rotationDictionary)
101
+ } else if let rotationDictionary = animatorDictionary[TextAnimatorKeys.rotationZ.rawValue] as? [String: Any] {
102
+ rotationZ = try? KeyframeGroup<LottieVector1D>(dictionary: rotationDictionary)
81
103
  } else {
82
- rotation = nil
104
+ rotationZ = nil
83
105
  }
106
+
84
107
  if let opacityDictionary = animatorDictionary[TextAnimatorKeys.opacity.rawValue] as? [String: Any] {
85
108
  opacity = try KeyframeGroup<LottieVector1D>(dictionary: opacityDictionary)
86
109
  } else {
@@ -107,8 +130,14 @@ final class TextAnimator: Codable, DictionaryInitializable {
107
130
  /// Skew Axis
108
131
  let skewAxis: KeyframeGroup<LottieVector1D>?
109
132
 
110
- /// Rotation
111
- let rotation: KeyframeGroup<LottieVector1D>?
133
+ /// Rotation on X axis
134
+ let rotationX: KeyframeGroup<LottieVector1D>?
135
+
136
+ /// Rotation on Y axis
137
+ let rotationY: KeyframeGroup<LottieVector1D>?
138
+
139
+ /// Rotation on Z axis
140
+ let rotationZ: KeyframeGroup<LottieVector1D>?
112
141
 
113
142
  /// Opacity
114
143
  let opacity: KeyframeGroup<LottieVector1D>?
@@ -159,6 +188,9 @@ final class TextAnimator: Codable, DictionaryInitializable {
159
188
  case skew = "sk"
160
189
  case skewAxis = "sa"
161
190
  case rotation = "r"
191
+ case rotationX = "rx"
192
+ case rotationY = "ry"
193
+ case rotationZ = "rz"
162
194
  case opacity = "o"
163
195
  }
164
196
  }
@@ -38,22 +38,18 @@ extension LottieColor: Codable {
38
38
  b1 = 0
39
39
  }
40
40
 
41
- var a1: Double
42
- if !container.isAtEnd {
43
- a1 = try container.decode(Double.self)
44
- } else {
45
- a1 = 1
46
- }
47
- if r1 > 1, g1 > 1, b1 > 1, a1 > 1 {
41
+ if r1 > 1, g1 > 1, b1 > 1 {
48
42
  r1 = r1 / 255
49
43
  g1 = g1 / 255
50
44
  b1 = b1 / 255
51
- a1 = a1 / 255
52
45
  }
53
46
  r = r1
54
47
  g = g1
55
48
  b = b1
56
- a = a1
49
+
50
+ // The Lottie JSON schema supports alpha values in theory, as the fourth value in this array.
51
+ // We intentionally do not support this, though, for consistency with Lottie on other platforms.
52
+ a = 1
57
53
  }
58
54
 
59
55
  // MARK: Public
@@ -79,17 +75,18 @@ extension LottieColor: AnyInitializable {
79
75
  var r: Double = array.count > 0 ? array.removeFirst() : 0
80
76
  var g: Double = array.count > 0 ? array.removeFirst() : 0
81
77
  var b: Double = array.count > 0 ? array.removeFirst() : 0
82
- var a: Double = array.count > 0 ? array.removeFirst() : 1
83
- if r > 1, g > 1, b > 1, a > 1 {
78
+ if r > 1, g > 1, b > 1 {
84
79
  r /= 255
85
80
  g /= 255
86
81
  b /= 255
87
- a /= 255
88
82
  }
89
83
  self.r = r
90
84
  self.g = g
91
85
  self.b = b
92
- self.a = a
86
+
87
+ // The Lottie JSON schema supports alpha values in theory, as the fourth value in this array.
88
+ // We intentionally do not support this, though, for consistency with Lottie on other platforms.
89
+ a = 1
93
90
  }
94
91
 
95
92
  }
@@ -246,6 +246,10 @@ extension CGSize {
246
246
 
247
247
  extension CATransform3D {
248
248
 
249
+ enum Axis {
250
+ case x, y, z
251
+ }
252
+
249
253
  static func makeSkew(skew: CGFloat, skewAxis: CGFloat) -> CATransform3D {
250
254
  let mCos = cos(skewAxis.toRadians())
251
255
  let mSin = sin(skewAxis.toRadians())
@@ -311,20 +315,37 @@ extension CATransform3D {
311
315
  anchor: CGPoint,
312
316
  position: CGPoint,
313
317
  scale: CGSize,
314
- rotation: CGFloat,
318
+ rotationX: CGFloat,
319
+ rotationY: CGFloat,
320
+ rotationZ: CGFloat,
315
321
  skew: CGFloat?,
316
322
  skewAxis: CGFloat?)
317
323
  -> CATransform3D
318
324
  {
319
325
  if let skew = skew, let skewAxis = skewAxis {
320
- return CATransform3DMakeTranslation(position.x, position.y, 0).rotated(rotation).skewed(skew: -skew, skewAxis: skewAxis)
321
- .scaled(scale * 0.01).translated(anchor * -1)
326
+ return CATransform3DMakeTranslation(position.x, position.y, 0)
327
+ .rotated(rotationX, axis: .x)
328
+ .rotated(rotationY, axis: .y)
329
+ .rotated(rotationZ, axis: .z)
330
+ .skewed(skew: -skew, skewAxis: skewAxis)
331
+ .scaled(scale * 0.01)
332
+ .translated(anchor * -1)
322
333
  }
323
- return CATransform3DMakeTranslation(position.x, position.y, 0).rotated(rotation).scaled(scale * 0.01).translated(anchor * -1)
334
+ return CATransform3DMakeTranslation(position.x, position.y, 0)
335
+ .rotated(rotationX, axis: .x)
336
+ .rotated(rotationY, axis: .y)
337
+ .rotated(rotationZ, axis: .z)
338
+ .scaled(scale * 0.01)
339
+ .translated(anchor * -1)
324
340
  }
325
341
 
326
- func rotated(_ degrees: CGFloat) -> CATransform3D {
327
- CATransform3DRotate(self, degrees.toRadians(), 0, 0, 1)
342
+ func rotated(_ degrees: CGFloat, axis: Axis) -> CATransform3D {
343
+ CATransform3DRotate(
344
+ self,
345
+ degrees.toRadians(),
346
+ axis == .x ? 1 : 0,
347
+ axis == .y ? 1 : 0,
348
+ axis == .z ? 1 : 0)
328
349
  }
329
350
 
330
351
  func translated(_ translation: CGPoint) -> CATransform3D {
@@ -338,4 +359,5 @@ extension CATransform3D {
338
359
  func skewed(skew: CGFloat, skewAxis: CGFloat) -> CATransform3D {
339
360
  CATransform3DConcat(CATransform3D.makeSkew(skew: skew, skewAxis: skewAxis), self)
340
361
  }
362
+
341
363
  }