Swiftgen: Add templates for Lottie

Created on 19 Mar 2019  Â·  12Comments  Â·  Source: SwiftGen/SwiftGen

It would be nice to have a template to handle Lottie animations

I've put together a quick template, but haven't have the occasion to test it in practice yet nor to refine it or write tests and documentation for it, so I'm just dumping it there for now.

  • If anyone wants to pick that feature up from there, don't hesitate to do so!
  • If you are using Lottie and want to give that template a try, feel free to copy/paste the template into a file and use it as a custom template with your SwiftGen and give us feedback on it!

Usage example

let view = LOTAnimationView(lottie: .intro1)
// or
let view = Lottie.intro1.makeView()

Template

Draft Template to generate constants for Lottie animations found in the scanned folder

// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen

{% if files %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
{% set enumName %}{{param.enumName|default:"Lottie"}}{% endset %}
import Foundation
import Lottie

// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length

// MARK: - Implementation Details

{{accessModifier}} struct {{enumName}} {
  let name: String
  let width: CGFloat
  let height: CGFloat

  func makeView() -> LOTAnimationView {
    return LOTAnimationView(lottie: self)
  }
}

{{accessModifier}} extension LOTAnimationView {
  init(lottie: {{enumName}}, fixSize: Bool = true) {
    self.init(name: lottie.name, bundle: Bundle(for: BundleToken.self))
    if fixSize {
      NSLayoutConstraint.activate([
        self.widthAnchor.constraint(equalToConstant: lottie.width),
        self.heightAnchor.constraint(equalToConstant: lottie.height)
      ])
    }
  }
}

// MARK: - Lotties

// swiftlint:disable identifier_name line_length number_separator type_body_length
{{accessModifier}} extension {{enumName}} {
  {% for file in files %}
  {% set width %}{{file.documents.first.data["w"]}}{% endset %}
  {% set height %}{{file.documents.first.data["h"]}}{% endset %}
  static let {{file.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = Lottie(name: "{{file.name}}", width: {{width}}, height: {{height}})
  {% endfor %}
}
// swiftlint:enable identifier_name line_length number_separator type_body_length

private final class BundleToken {}
{% else %}
// No files found
{% endif %}

Output example

// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen

import Foundation
import Lottie

// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length

// MARK: - Implementation Details

internal struct Lottie {
  let name: String
  let width: CGFloat
  let height: CGFloat

  func makeView() -> LOTAnimationView {
    return LOTAnimationView(lottie: self)
  }
}

internal extension LOTAnimationView {
  init(lottie: Lottie, fixSize: Bool = true) {
    self.init(name: lottie.name, bundle: Bundle(for: BundleToken.self))
    if fixSize {
      NSLayoutConstraint.activate([
        self.widthAnchor.constraint(equalToConstant: lottie.width),
        self.heightAnchor.constraint(equalToConstant: lottie.height)
      ])
    }
  }
}

// MARK: - Lotties

// swiftlint:disable identifier_name line_length number_separator type_body_length
internal extension Lottie {
  static let hold = Lottie(name: "hold", width: 600, height: 600)
  static let intro1 = Lottie(name: "intro_1", width: 600, height: 600)
  static let intro2 = Lottie(name: "intro_2", width: 600, height: 600)
  static let intro3 = Lottie(name: "intro_3", width: 600, height: 600)
  static let tick = Lottie(name: "tick", width: 600, height: 600)
}
// swiftlint:enable identifier_name line_length number_separator type_body_length

private final class BundleToken {}
Just a custom template away! Easiest way to contribute! enhancement

Most helpful comment

Hello,
Thanks for your help guys, at the end I got it.

I have created a more simple template than the one offered by @AliSoftware and @djbe, that adjust better to our way of using it in the code.

Anyway I let it here, in case is useful for you:

// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen

{% if files %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
{% set enumName %}{{param.enumName|default:"Lottie"}}{% endset %}
import Foundation
import Lottie

// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length

// MARK: - Lottie Files Enum

// swiftlint:disable identifier_name line_length number_separator type_body_length
{{accessModifier}} enum {{enumName}} {
  {% for file in files %}
  {{accessModifier}} static let {{file.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = Animation.named("{{file.name}}")!
  {% endfor %}
}
// swiftlint:enable identifier_name line_length number_separator type_body_length

// swiftlint:disable convenience_type
private final class BundleToken {
  static let bundle: Bundle = {
    Bundle(for: BundleToken.self)
  }()
}
// swiftlint:enable convenience_type

{% else %}
// No files found
{% endif %}

And on the other hand, IMO is still not clear how to use custom templates in the docs, was the most difficult part that I faced, so I let also my configuration here

json:
    inputs:
        - Resources/Lottie/
    outputs:
        templatePath: SwiftGenTemplates/Lottie.stencil
        output: Generated/Lottie.swift

Finally, this is the generated code:

// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen

import Foundation
import Lottie

// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length

// MARK: - Lottie Files Enum

// swiftlint:disable identifier_name line_length number_separator type_body_length
internal enum Lottie {
  internal static let loadingScreen = Animation.named("loadingScreen")!
  internal static let technicalProblem = Animation.named("technicalProblem")!
  internal static let tick = Animation.named("tick")!
  internal static let updateApp = Animation.named("updateApp")!
  internal static let upgradePasscodePopup = Animation.named("upgradePasscodePopup")!
  internal static let verifyEmail = Animation.named("verifyEmail")!
}
// swiftlint:enable identifier_name line_length number_separator type_body_length

// swiftlint:disable convenience_type
private final class BundleToken {
  static let bundle: Bundle = {
    Bundle(for: BundleToken.self)
  }()
}
// swiftlint:enable convenience_type

Thanks in advance!

All 12 comments

Huh, funny, we also have an internal template for lottie animations 😆 Lemme dig it up.

@djbe yours fails with invalidInputType when I pass it my folder containing Lottie JSON files. works only if I pass one json file. (Maybe we have some file in that folder that has a JSON key that you expect but is missing in our animation?)

Yeah dunno, might depend on some export options? It looks for the short version of key names for example. Or maybe the version of the Lottie format?

The main use for us is to load animations, and to be able to change the color of certain elements (or the whole thing). But as you'll note the way to change those is really bizarre and very limited.

Just started using the original/above template with a couple of minor mods: added an allCases static for admin/debugging purposes and needed to make the LOTAnimationView init into a convenient init. Perhaps can contribute back with a PR once we verify this is doing the job.

@djbe By any chance do you have an update template for Lottie 3 ?

Nope, sorry, we haven't used it since we tried it out in one project. The template is pretty simple though, should be easy enough to update given a sample file.

Do note that Lottie now also has a Swift SDK, with better API? (not sure) Maybe the template has become redundant?

Lottie version 3 is the Swift version, I guess a template is still useful, will see if I can adapt yours, thanks !

Hello, first of all, thank you very much for this useful template,
Maybe this is a stupid question, but I don't know how to include this custom template for Lottie files in the
swiftgen.yml
Can you put here an example???

Please!

The way to use and create custom templates is all documented in the README here and even in more details in that dedicated doc

Basically just save the template somewhere in your repo, then use templatePath as the key in your swiftgen.yml to point to the relative path to it.

Hello,
Thanks for your help guys, at the end I got it.

I have created a more simple template than the one offered by @AliSoftware and @djbe, that adjust better to our way of using it in the code.

Anyway I let it here, in case is useful for you:

// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen

{% if files %}
{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %}
{% set enumName %}{{param.enumName|default:"Lottie"}}{% endset %}
import Foundation
import Lottie

// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length

// MARK: - Lottie Files Enum

// swiftlint:disable identifier_name line_length number_separator type_body_length
{{accessModifier}} enum {{enumName}} {
  {% for file in files %}
  {{accessModifier}} static let {{file.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = Animation.named("{{file.name}}")!
  {% endfor %}
}
// swiftlint:enable identifier_name line_length number_separator type_body_length

// swiftlint:disable convenience_type
private final class BundleToken {
  static let bundle: Bundle = {
    Bundle(for: BundleToken.self)
  }()
}
// swiftlint:enable convenience_type

{% else %}
// No files found
{% endif %}

And on the other hand, IMO is still not clear how to use custom templates in the docs, was the most difficult part that I faced, so I let also my configuration here

json:
    inputs:
        - Resources/Lottie/
    outputs:
        templatePath: SwiftGenTemplates/Lottie.stencil
        output: Generated/Lottie.swift

Finally, this is the generated code:

// swiftlint:disable all
// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen

import Foundation
import Lottie

// swiftlint:disable superfluous_disable_command
// swiftlint:disable file_length

// MARK: - Lottie Files Enum

// swiftlint:disable identifier_name line_length number_separator type_body_length
internal enum Lottie {
  internal static let loadingScreen = Animation.named("loadingScreen")!
  internal static let technicalProblem = Animation.named("technicalProblem")!
  internal static let tick = Animation.named("tick")!
  internal static let updateApp = Animation.named("updateApp")!
  internal static let upgradePasscodePopup = Animation.named("upgradePasscodePopup")!
  internal static let verifyEmail = Animation.named("verifyEmail")!
}
// swiftlint:enable identifier_name line_length number_separator type_body_length

// swiftlint:disable convenience_type
private final class BundleToken {
  static let bundle: Bundle = {
    Bundle(for: BundleToken.self)
  }()
}
// swiftlint:enable convenience_type

Thanks in advance!

Perfekt @fjtrujy :) thanks for the solution ^^

Was this page helpful?
0 / 5 - 0 ratings

Related issues

djbe picture djbe  Â·  6Comments

AliSoftware picture AliSoftware  Â·  6Comments

gereons picture gereons  Â·  5Comments

valerianb picture valerianb  Â·  7Comments

razor313 picture razor313  Â·  6Comments