适用于 Xcode 13.0 和 MacOS 12.0
被卡住了,无法让 Lottie 在 macOS 本机应用程序上工作来加载动画,因为在我在线查看的所有教程中,Lottie 框架将其链接到 swiftUI 需要使用 UIViewRepresentable,而这在 macOS 上不可用唯一的应用程序。经过一些工作和修补后,终于使用 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> ) {
}
}
**唯一的事情是,您还必须使用传递给 NSViewRepresntable 的相同宽度和高度参数来构建视图,这样:
LottieView(filename: "cloudSyncAnimation", speed: 1.0, loop: .loop, heightView: 100, widthView: 100).frame(width: 100, height: 100, alignment: .center)
希望有人能发现这个解决方案有用,可能不是最简单或最优雅的解决方案,但有效,而且我对 swift 相当陌生,所以任何贡献将不胜感激
我对动画的大小也有同样的问题。 我的猜测是,animationView 试图首先获取原始动画的大小,因此我删除了内容阻力优先级。
这是我的实现:
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) {
}
}
无需包装纸或设置固定尺寸。
这个解决方案对我有用:
import AppKit
import DotLottie
import Lottie
import SwiftUI
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 = LottieAnimationView()
public func makeNSView(context: Context) -> some NSView {
let theView = NSView()
animationView.animation = LottieAnimation.named(lottieFile)
animationView.contentMode = .scaleAspectFit
animationView.loopMode = loopMode
animationView.backgroundBehavior = .continuePlaying
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) {
}
}