让 Lottie 与 macOS 和 AppKit 配合使用(无需 UIKit)

问题描述 投票:0回答:2

适用于 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 相当陌生,所以任何贡献将不胜感激

swift swiftui uikit appkit lottie
2个回答
3
投票

我对动画的大小也有同样的问题。 我的猜测是,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) {
        
    }
}

无需包装纸或设置固定尺寸。


0
投票

这个解决方案对我有用:

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) {

  }
}
© www.soinside.com 2019 - 2024. All rights reserved.