Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lottie 3.0 - A complete rewrite of Lottie in Swift! #777

Merged
merged 12 commits into from
Mar 17, 2019
Merged

Conversation

buba447
Copy link
Collaborator

@buba447 buba447 commented Mar 11, 2019

Lottie 3.0 Now in Swift!

This PR removes the old Objective-C implementation of Lottie and replaces it, in its entirety, with a Swift implementation. With this comes many bug fixes, and new features.

Migrating

Lottie 3.0 is a complete rewrite of Lottie in Swift 4.0! Please Note that the Api and Class names have changed slightly. (No more LOT prefix). Read About Migrating Here

Legacy Objective C Support

To continue using, and contributing to, the Obj-c version of Lottie point to this branch objectiveC

New Features

In addition to completely rebuilding the entire animation engine, several new features have been added:

  • New documentation fully covers Lottie API.
  • Text Rendering (No Glyphs) now supported
  • Gradient Stroke now supported
  • Individual Trim paths now supported
  • Alpha inverted masks now supprted
  • Marker support
  • Skew now supported
  • Fully support all UIView content modes
  • New api for dynamic properties.
  • Animation now fully supports Codable. You can decode and encode JSON data.
  • Animated Button component
  • New more flexible ImageProvider
  • Play animations in their native framerate
  • Read animation progress in realtime
  • Spatial Interpolation now more accurate
  • Added API for getting animation properties
  • Rewritten render system, fixing many bugs.
  • JSON Decoding supports Default values
  • JSON Coding unit testing
  • Trim paths are now more accurate
  • Bug fixes, bug fixes, bug fixes.

New Documentation

Documentation has also been completely revamped here. A new contributor documentation has been written that runs through the tech side of Lottie here

@Coeur
Copy link
Contributor

Coeur commented Mar 12, 2019

Please see #780 (a Pull Request targeting your branch), with some impact on public API:

  • backgroundBehvior renamed backgroundBehavior
  • textOuputNode renamed textOutputNode
  • etc.

@Coeur
Copy link
Contributor

Coeur commented Mar 12, 2019

A little bit sad that:

  1. You did many fundamental changes instead of offering a direct conversion from the existing Objective-C implementation. This means that this PR may break (or solve) things which are unrelated to a Swift migration: it doesn't make it easy to review. The new features could have come as a separate PR, for easier reviewing.
  2. You removed the existing tests instead of converting them, which makes it even harder to ensure that you're not breaking anything: this framework is not just to display the Lottie logo. ;)

But happy that it's now on Swift and happy of the changelog.

Copy link
Contributor

@Coeur Coeur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, just a quick partial overall overview. I wouldn't have enough time to review it fully.

extension MaskMode {
var usableMode: MaskMode {
switch self {
case .add:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just need one case for lighten, one case for difference, and the rest as default: return self.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the full list of mask modes supported by body movin. If we add it, code will come 👍


extension CGRect {
static var veryLargeRect: CGRect {
return CGRect(x: -100000000,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SwiftLint would recommend to separate thousands as in -100_000_000.


let frameRate: CGFloat
let remappingNode: NodeProperty<Vector1D>?
fileprivate var animationLayers: [CompositionLayer]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with fileprivate var animationLayers: [CompositionLayer] = [], we wouldn't need to explicitly set it in init functions.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer it this way, so if additional initializers are added the compiler will tell you to handle animationLayers

init(imageProvider: AnimationImageProvider, assets: [String : ImageAsset]?) {
self.imageProvider = imageProvider
self.imageLayers = [ImageCompositionLayer]()
if let assets = assets {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simply use the nil coalescing operator: self.imageAssets = assets ?? [:]


var image: CGImage? = nil {
didSet {
if let image = image {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for if/else, directly write: contentsLayer.contents = image



// Scale
self.scale = try container.decodeIfPresent(KeyframeGroup<Vector3D>.self, forKey: .scale) ?? KeyframeGroup(Vector3D(x: Double(100), y: 100, z: 100))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There aren't any overload for this initializer of Vector3D, so the explicit cast to Double is not needed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Theres one for CGFloat and Double

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, right, I didn't notice the private extension earlier.
Note that personally I would have wrote it 100 as Double, but it's fine. ;)


- Returns: Deseralized `Animation`. Optional.
*/
public static func named(_ name: String,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Xcode 10.2 will warn for all users: 'public' modifier is redundant for static method declared in a public extension.

}

/// Make sure the file exists.
guard FileManager.default.fileExists(atPath: filepath) else {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using fileExists is against Apple recommendations. Apple advices to directly attempt the file operation without it. See the note of https://developer.apple.com/documentation/foundation/filemanager/1415645-fileexists

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@buba447
Copy link
Collaborator Author

buba447 commented Mar 12, 2019

@Coeur

  1. What fundamental changes are you referring to? I tried to keep the api as close as possible to the objective c while also respecting swift code styling.

  2. The tests still exist! They have been moved to a private repo that also contains about 2,000 animations from other companies that wish to keep their IP private. There are actually more tests now than ever before. I've added tests that also test the json encoding/decoding. Im happy to report that all tests pass as well.

@Coeur
Copy link
Contributor

Coeur commented Mar 12, 2019

Oh, I wasn't aware of the private repo with the tests. Then it's all good. Changes approved. :)

Just try to fix the "'public' modifier is redundant" warnings from Xcode 10.2 before releasing.

@thedrick
Copy link
Contributor

@Coeur thanks so much for giving this a review! Just wanted to let you know that Airbnb is now using this version of Lottie in our production app and I've tested all of our animations using it. Really appreciate all of your feedback :) (and +1 to fixing the public modifier warnings)

buba447 and others added 3 commits March 13, 2019 12:32
This fixes warnings in Xcode 10.2 related to access modifiers
fatalError("init(layer:) Wrong Layer Class")
}
self.imageReferenceID = layer.imageReferenceID
self.image = nil
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that image is already defaulted to nil, would this line be necessary?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely not necessary.

}

func addImageLayers(_ layers: [ImageCompositionLayer]) {
for layer in layers {
Copy link

@vlozko vlozko Mar 14, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if it's too unreadable but this can be written with a two-liner:

let foundLayers = layers.filter { imageAssets[$0.imageReferenceID] != nil }
imageLayers.append(contentsOf: foundLayers)

self.markers = try container.decodeIfPresent([Marker].self, forKey: .markers)

if let markers = markers {
var markerMap: [String : Marker] = [:]
Copy link

@vlozko vlozko Mar 14, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any thoughts on writing this whole if-let-else statement to this?

self.markerMap = markers?.reduce([String : Marker](),  { markerMap,  marker, in
    markerMap[marker.name] = marker
}

Copy link
Contributor

@Coeur Coeur Mar 15, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reduce(::) will copy the dictionary at each iteration. You should use reduce(into::) for this!

Copy link

@vlozko vlozko Mar 15, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You’re right, I did mean reduce(into::) as my code probably won’t compile.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@skborhan
Copy link

skborhan commented Sep 13, 2019

HI, Im trying to add Lottie (animated sticker) in video. I can export it but I can't play it in runtime AVSynchronizedLayer. Is there any way to use Lottie view/layer in avsynchronizedlayer? Im using Lottie - 2.5.2 (Objective C).

@Coeur
Copy link
Contributor

Coeur commented Sep 17, 2019

@skborhan please fill a new GitHub issue or a StackOverflow question for a matter that isn't directly related to the review of the pull request, thank you.

@buba447 buba447 deleted the btw/lottie-swift branch November 25, 2019 16:46
NSGolova pushed a commit to clario-tech/lottie-ios that referenced this pull request Nov 19, 2020
Lottie 3.0 - A complete rewrite of Lottie in Swift!
calda pushed a commit that referenced this pull request Dec 1, 2022
Lottie 3.0 - A complete rewrite of Lottie in Swift!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants