SwiftUI воспроизводит анимацию 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)
        
    }
}
}

У меня есть привязка bool, которая должна меняться либо на true, либо на false, когда я нажимаю на кнопку. Другими словами, когда я нажимаю кнопку, я должен иметь возможность играть и останавливать ее. Но почему-то это логическое значение не разделяется между структурами, и анимация воспроизводится постоянно. Я новичок в быстром пользовательском интерфейсе, поэтому предполагаю, что делаю что-то очень не так, поэтому буду признателен за некоторую помощь.

Здесь вы можете увидеть мою анимацию


person Dakata    schedule 04.07.2020    source источник


Ответы (1)


Вы почти получили это. Вам необходимо создать Coordinator, чтобы вы могли получить доступ к значениям внутри вашего LottieView. Это просто сделать.

  1. Создайте Coordinator класс, соответствующий NSObject
  2. Передайте свой LottieView.
  3. Добавьте функцию makeCoordinator в свой LottieView
  4. Создайте экземпляр вашего Coordinator в функции makeCoordinator
  5. В вашем updateUIView войдите в animationView из coordinator.

Вам не нужна привязка для isAnimating, поскольку LottieView не передает никакой информации обратно в ваш ContentView. Вам также не нужен @State для name

Вот как я заставил Лотти играть и приостанавливать работу в своих приложениях. Обратите внимание, что некоторые имена переменных отличаются от ваших, но этого должно быть достаточно, чтобы вы оказались в нужном месте.

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")
            })
        }

    }
}

Вот это работает:

Воспроизведение анимации и пауза при нажатии кнопки

person Andrew    schedule 04.07.2020
comment
Эй, один вопрос. Вы знаете, как я могу воспроизвести его до загрузки представления? Потому что я получаю данные с сервера и хочу воспроизвести анимацию во время загрузки данных. Сейчас он запускается только тогда, когда представление полностью загружено на экран. Спасибо тебе, друг! - person Dakata; 04.07.2020
comment
Это действительно зависит от того, как вы представляете экран загрузки. В идеале у вас должна быть некоторая переменная состояния, которая определяет состояние вашего экрана (основными состояниями обычно являются загрузка, загрузка, ошибка). То, как вы обрабатываете эти состояния и представляете основанные на них представления, может быть довольно сложным или тривиальным в зависимости от вашей настройки. Я думаю, что нельзя было бы хорошо ответить на ваш вопрос в комментарии. - person Andrew; 04.07.2020
comment
Большое тебе спасибо. У вас случайно есть примеры из ваших проектов? - person Dakata; 05.07.2020
comment
Краткое приложение: если вы - как и я - не зацикливаете анимацию, а воспроизводите ее только один раз и хотите, чтобы она воспроизводилась снова при следующем нажатии кнопки, я изменил часть updateUIView else на: context.coordinator.parent.animationView.play { (_) in context.coordinator.parent.isPaused = true }, чтобы она снова автоматически приостанавливалась после проигрывается анимация. :) - person mmika1000; 01.03.2021