Animation 如何在SwiftUI中启用乐蒂按钮动画的操作?

Animation 如何在SwiftUI中启用乐蒂按钮动画的操作?,animation,swiftui,lottie,lottie-ios,Animation,Swiftui,Lottie,Lottie Ios,我有一个简单的项目,当点击一个按钮时运行一个乐蒂动画 struct ContentView: View { @State var number = 0 @State var toogleValue : Bool = false var body: some View { ZStack { Color.green.opacity(0.2) ZStack { LottieButton(filename: "17247-ha

我有一个简单的项目,当点击一个按钮时运行一个乐蒂动画

struct ContentView: View {

@State var number = 0
@State var toogleValue : Bool = false

var body: some View {
    ZStack {
        Color.green.opacity(0.2)
        ZStack {
            LottieButton(filename: "17247-happy-flower")
               .frame(width: 200)
               .onTapGesture {
                    self.number += 1
            }
            Text("number = \(self.number)")
            .offset( y: 150)
        }
    }.edgesIgnoringSafeArea(.all)
}
}
我试图实现的是:每当用户点击按钮时,动画就会开始,数字计数器就会增加1

现在发生的情况:计数器增加1,但动画未播放

我尝试的内容:当我注释//ontapsignate{self.number+=1}时,动画工作正常,但是计数器不工作

这是乐透按钮:

  struct LottieButton: UIViewRepresentable {
/// Create a button.
let animationButton = AnimatedButton()
var filename = "LottieLogo2"

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

let animation = Animation.named(filename)
animationButton.animation = animation
animationButton.contentMode = .scaleAspectFit

animationButton.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(animationButton)

animationButton.clipsToBounds = false
   /// Set animation play ranges for touch states
animationButton.setPlayRange(fromMarker: "touchDownStart", toMarker: "touchDownEnd", event: .touchUpInside)
 //  animationButton.setPlayRange(fromMarker: "touchDownEnd", toMarker: "touchUpCancel", event: .touchUpOutside)
 //  animationButton.setPlayRange(fromMarker: "touchDownEnd", toMarker: "touchUpEnd", event: .touchUpInside)
                                 
NSLayoutConstraint.activate([
    animationButton.heightAnchor.constraint(equalTo: view.heightAnchor),
    animationButton.widthAnchor.constraint(equalTo: view.widthAnchor),
])

return view
}

func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<LottieButton>) {
         
}
}
struct LottieButton:UIViewRepresentable{
///创建一个按钮。
让animationButton=AnimatedButton()
var filename=“LottieLogo2”
func makeUIView(上下文:UIViewRepresentableContext)->UIView{
let view=UIView()
让animation=animation.named(文件名)
animationButton.animation=动画
animationButton.contentMode=.ScaleSpectFit
animationButton.TranslatesAutoResizezingMaskintoConstraints=false
view.addSubview(动画按钮)
animationButton.clipsToBounds=false
///设置触摸状态的动画播放范围
animationButton.setPlayRange(从Marker:“touchDownStart”到Marker:“touchDownEnd”,事件:.touchUpInside)
//animationButton.setPlayRange(从Marker:“touchDownEnd”到Marker:“touchUpCancel”,事件:.touchUpOutside)
//animationButton.setPlayRange(从Marker:“touchDownEnd”到Marker:“touchUpEnd”,事件:.touchUpInside)
NSLayoutConstraint.activate([
animationButton.heightAnchor.constraint(相等于:view.heightAnchor),
animationButton.widthAnchor.constraint(equalTo:view.widthAnchor),
])
返回视图
}
func updateUIView(uiView:uiView,context:UIViewRepresentableContext){
}
}
我假设问题是由于视图的层次结构造成的,但我不是很确定,因为我是SwiftUI的初学者,因此我希望得到一些帮助。

您需要使用
协调器,该协调器可与
UIViewRepresentable一起使用

通过使用
协调器
类,可以将目标添加到
动画视图
。Targets和Objective-C公开函数只能添加到类中。这意味着您可以在点击动画时执行任何操作

向我们的
LottieButton
结构传递两个参数a
filename
和一个
action
。这个动作基本上是一个闭包,允许我们传递一段代码,稍后执行

我们通过将引用传递给正在创建的
LottieButton
来设置
协调器,然后添加目标。这需要在调用
super.init
之后添加,因为我们需要用户
self

import SwiftUI
import Lottie

struct LottieButton: UIViewRepresentable {

    typealias UIViewType = UIView
    let animationView = AnimatedButton()
    let filename: String
    let action: () -> Void

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

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

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

    }

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


    class Coordinator: NSObject {
        let parent: LottieButton

        init(_ parent: LottieButton) {
            self.parent = parent
            super.init()
            parent.animationView.addTarget(self, action: #selector(touchUpInside), for: .touchUpInside)
        }

        // this function can be called anything, but it is best to make the names clear
        @objc func touchUpInside() {
            parent.action()
        }
    }
}
这就是它的工作原理:


您是否有关于如何在获取数据时播放动画并在数据加载到屏幕上时停止的示例教程?我仍在为这个问题挣扎。
struct ContentView: View {

    @State private var tapped: Int = 0

    var body: some View {
        VStack {
            LottieButton(filename: "loading", action: {
                print("tapped")
                tapped += 1
            })
            .frame(width: 200, height: 200)

            Text("tapped count \(tapped)")
        }
    }
}