Works on Xcode 13.0 and MacOS 12.0
Was stuck and was unable to make Lottie work on an macOS native app to load the animation since the Lottie framework to link it to swiftUI on all the tutorial that I have looked online require the use of UIViewRepresentable, which is not available on a macOS only app. So after some work and tinkering, finally made it work using NSViewPresentable
struct LottieView: NSViewRepresentable {
//To allow the JSON file to be read and to display the animaton
//Allows link to SwiftUI from NSView()
let animationView = AnimationView()
var filename : String //The name of the file to be loaded
var speed: Double //The speed at which the animation should be played
var loop: LottieLoopMode //Whever the animation should loop
var heightView: Double
var widthView: Double
func makeNSView(context: NSViewRepresentableContext<LottieView>) -> NSView {
let view = NSView()
let animation = Animation.named(filename) //Loads the animation
animationView.animation = animation //Sets the animation
animationView.animationSpeed = CGFloat(speed) //Speed
animationView.contentMode = .scaleAspectFit //Aspect Ratio
animationView.loopMode = loop //Whever to loop
animationView.play() //Plays the animation
animationView
.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(animationView)
view.setFrameSize(CGSize(width: 100, height: 100))
NSLayoutConstraint.activate([
animationView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
animationView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
animationView.heightAnchor.constraint(equalToConstant: heightView),
animationView.widthAnchor.constraint(equalToConstant: widthView)
])
return view //Necessary in order to conform to UIVieewRepresentable
}
func updateNSView(_ uiView: NSView, context: NSViewRepresentableContext<LottieView> ) {
}
}
**the only thing is that you have also to frame the view with the same width and height parameter passed to the NSViewRepresntable such that:
LottieView(filename: "cloudSyncAnimation", speed: 1.0, loop: .loop, heightView: 100, widthView: 100).frame(width: 100, height: 100, alignment: .center)
Hopefully someone can find this solution useful, probably not the most simple or elegant solution but works and I am fairly new to swift so any contribution would be appreciated
I was having the same problem with the size of the animation. My guess was that the animationView was trying to first take the size of the original animation, so I removed the content resistance priority.
This is my implementation:
public struct LottieView: NSViewRepresentable{
public init(lottieFile: String, loopMode: LottieLoopMode = .loop, autostart: Bool = true, contentMode: LottieContentMode = LottieContentMode.scaleAspectFit) {
self.lottieFile = lottieFile
self.loopMode = loopMode
self.autostart = autostart
self.contentMode = contentMode
}
let lottieFile: String
let loopMode: LottieLoopMode
let autostart: Bool
let contentMode: LottieContentMode
let animationView = AnimationView()
public func makeNSView(context: Context) -> some NSView {
let theView = NSView()
animationView.animation = Animation.named(lottieFile)
animationView.contentMode = .scaleAspectFit
animationView.loopMode = loopMode
animationView.backgroundBehavior = .pauseAndRestore
if self.autostart{
animationView.play()
}
theView.addSubview(animationView)
animationView.translatesAutoresizingMaskIntoConstraints = false
animationView.heightAnchor.constraint(equalTo: theView.heightAnchor).isActive = true
animationView.widthAnchor.constraint(equalTo: theView.widthAnchor).isActive = true
animationView.leadingAnchor.constraint(equalTo: theView.leadingAnchor).isActive = true
animationView.trailingAnchor.constraint(equalTo: theView.trailingAnchor).isActive = true
animationView.setContentCompressionResistancePriority(.defaultLow, for: .vertical)
animationView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
return theView
}
func pause(){
animationView.pause()
}
func play(){
animationView.play()
}
func stop(){
animationView.stop()
}
public func updateNSView(_ nsView: NSViewType, context: Context) {
}
}
No need to have a wrapper or set a fixed size.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With