SwiftUI 播放 Lottie 动画。

4

最近,我在玩Lottie动画,但是我遇到了一个问题,就是如何将它们从视图中停止。

这是我的ContentView,在这里我正在播放动画。我有一个按钮可以实时显示布尔值:

struct ContentView: View {

@State var isShowing : Bool = true

var body: some View {
    ZStack {
         Color.green.opacity(0.3)
        VStack {
            VStack {
                LottieDosi(isShowing: .constant(isShowing)){Text("")}
                Button(action: {self.isShowing.toggle()}) {
                    
                    Text("Button is \(String(isShowing))")
                    .padding(10)
                    .background(Color.white)
                    .cornerRadius(40)
                }
            }.padding(.horizontal, 30)
        }
    }.edgesIgnoringSafeArea(.all)
}
} 

这是我的 LottieView:

struct LottieView: UIViewRepresentable {

 @Binding var isAnimating: Bool
 @State   var name  : String

 var loopMode: LottieLoopMode = .loop
 var animationView = AnimationView()

 func makeUIView(context: UIViewRepresentableContext<LottieView>) -> UIView {
   let view = UIView()

   animationView.animation = Animation.named(name)
   animationView.contentMode = .scaleAspectFill
   animationView.loopMode = .loop
   animationView.play()

   animationView.translatesAutoresizingMaskIntoConstraints = false
   view.addSubview(animationView)

   NSLayoutConstraint.activate([
       animationView.widthAnchor.constraint(equalTo: view.widthAnchor),
       animationView.heightAnchor.constraint(equalTo: view.heightAnchor)
   ])

return view
}

func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<LottieView>) {
    isAnimating ? animationView.play() : animationView.stop()
}
}

struct LottieDosi<Content>:  View where Content: View {

@Binding var isShowing: Bool
var content: () -> Content

var body: some View {
    
    VStack {

          LottieView(isAnimating: .constant(isShowing), name: "13728-sticker-4")
            .frame(width: 175, height: 175)
        
    }
}
}

我有一个布尔类型绑定,每当我点击按钮时都必须将其更改为true或false。换句话说,当我按下按钮时,应该能够播放和停止它。但是不知何故,这个布尔值在结构之间没有共享,动画一直在播放。我对Swift UI还很陌生,因此我认为我做错了一些事情,所以我希望得到一些帮助。
这里您可以看到我的动画
1个回答

12
你已经接近成功了。你需要构造一个 Coordinator ,以便可以访问你的 LottieView 中的值。这很容易做到。
  1. 创建一个符合 NSObject 协议的 Coordinator 类。
  2. 传入你的 LottieView
  3. 为你的 LottieView 添加 makeCoordinator 函数。
  4. makeCoordinator 函数中创建你的 Coordinator 实例。
  5. 在你的 updateUIView 中通过 coordinator 访问 animationView

由于 LottieView 没有向你的 ContentView 返回任何信息,所以你不需要为 isAnimating 创建绑定。此外,你也不需要为 name 创建那个 @State

以下是我如何在我的应用程序中播放和暂停 Lottie 动画。请注意,一些变量名与你的不同,但应该足以让你达到目标。

import SwiftUI
import Lottie

struct LottieView: UIViewRepresentable {
    typealias UIViewType = UIView
    let filename: String
    let animationView = AnimationView()
    let isPaused: Bool

    func makeUIView(context: UIViewRepresentableContext<LottieView>) -> UIView {
        let view = UIView(frame: .zero)

        let animation = Animation.named(filename)
        animationView.animation = animation
        animationView.contentMode = .scaleAspectFit
        animationView.loopMode = .loop

        animationView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(animationView)

        NSLayoutConstraint.activate([
            animationView.widthAnchor.constraint(equalTo: view.widthAnchor),
            animationView.heightAnchor.constraint(equalTo: view.heightAnchor),
        ])

        return view
    }

    func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<LottieView>) {
        if isPaused {
            context.coordinator.parent.animationView.pause()
        } else {
            context.coordinator.parent.animationView.play()

        }
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject {
        var parent: LottieView

        init(_ parent: LottieView) {
            self.parent = parent
        }
    }
}

我的ContentView如下所示:

struct ContentView: View {

    @State private var isPaused: Bool = true

    var body: some View {
        VStack {
            LottieView(filename: "loading", isPaused: isPaused)
                .frame(width: 200, height: 200)
            Button(action: {
                self.isPaused.toggle()
            }, label: {
                Text(isPaused ? "Play" : "Pause")
            })
        }

    }
}

这里是它的工作效果:

点击按钮可以播放和暂停动画


嘿,有一个问题。你知道我怎么在视图加载之前播放它吗?因为我正在从服务器获取数据,并且我想在数据加载时播放动画。现在它只有在视图完全加载到屏幕上时才开始。谢谢伙计! - Dakata
这真的取决于你如何呈现加载屏幕。理想情况下,你应该有一些状态变量来确定屏幕的状态(主要状态通常是加载、已加载、错误)。根据这些状态处理和呈现视图可能会非常复杂或微不足道,这取决于你的设置。我认为在评论中很难回答你的问题。 - Andrew
非常感谢。你有没有你的项目中的任何示例呢? - Dakata
1
一个简短的附录:如果你和我一样,不希望动画循环播放,而只想它在按钮下一次点击时再次播放,那么我调整了updateUIView的“else”部分:context.coordinator.parent.animationView.play { (_) in context.coordinator.parent.isPaused = true } ,这样当动画播放完毕后,它会自动暂停。 :) - emmics
非常感谢,Lottie上的UIRepresentable简化版本在播放/暂停方面无法正常工作。 - malcolmp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接