SwiftUI - пульсирующая анимация и изменение цвета - PullRequest
2 голосов
/ 09 февраля 2020

Я пытаюсь изменить цвет моей анимации в зависимости от состояния чего-либо. Изменение цвета работает, но оно оживляет предыдущий (оранжевый) цвет с ним. Я не могу понять, почему оба цвета показывают. Есть идеи?

struct PulsatingView: View {

    var state = 1

    func colourToShow() -> Color {
        switch state {
        case 0:
            return Color.red
        case 1:
            return Color.orange
        case 2:
            return Color.green
        default:
            return Color.orange
        }
    }

    @State var animate = false
    var body: some View {
        VStack {
            ZStack {
                Circle().fill(colourToShow().opacity(0.25)).frame(width: 40, height: 40).scaleEffect(self.animate ? 1 : 0)
                Circle().fill(colourToShow().opacity(0.35)).frame(width: 30, height: 30).scaleEffect(self.animate ? 1 : 0)
                Circle().fill(colourToShow().opacity(0.45)).frame(width: 15, height: 15).scaleEffect(self.animate ? 1 : 0)
                Circle().fill(colourToShow()).frame(width: 6.25, height: 6.25)
            }
            .onAppear { self.animate.toggle() }
            .animation(Animation.easeInOut(duration: 1.5).repeatForever(autoreverses: true))
        }
    }
}

1 Ответ

1 голос
/ 09 февраля 2020

Вы меняете цвет, но анимируемый вид, который настроен навсегда , не изменяется - он остается установленным и продолжается, как указано, - навсегда. Поэтому необходимо переустановить анимацию.

Ниже приведен рабочий демонстрационный код полного модуля (протестирован с Xcode 11.2 / iOS 13.2). Идея состоит в том, чтобы использовать ObservableObject модель просмотра, поскольку она позволяет и обновлять sh просмотр и выполнять некоторые действия при получении. Таким образом, получая изменения цвета можно сбросить и просмотреть цвет и анимацию.

import SwiftUI
import Combine

class PulsatingViewModel: ObservableObject {
    @Published var colorIndex = 1
}

struct PulsatingView: View {

    @ObservedObject var viewModel: PulsatingViewModel

    func colourToShow() -> Color {
        switch viewModel.colorIndex {
        case 0:
            return Color.red
        case 1:
            return Color.orange
        case 2:
            return Color.green
        default:
            return Color.orange
        }
    }

    @State var animate = false
    var body: some View {
        VStack {
            ZStack {
                Circle().fill(colourToShow().opacity(0.25)).frame(width: 40, height: 40).scaleEffect(self.animate ? 1 : 0)
                Circle().fill(colourToShow().opacity(0.35)).frame(width: 30, height: 30).scaleEffect(self.animate ? 1 : 0)
                Circle().fill(colourToShow().opacity(0.45)).frame(width: 15, height: 15).scaleEffect(self.animate ? 1 : 0)
                Circle().fill(colourToShow()).frame(width: 6.25, height: 6.25)
            }
            .onAppear { self.animate = true }
            .animation(animate ? Animation.easeInOut(duration: 1.5).repeatForever(autoreverses: true) : .default)
            .onReceive(viewModel.$colorIndex) { _ in
                self.animate = false
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                    self.animate = true
                }
            }
        }
    }
}

struct TestPulseColorView: View {
    private var model = PulsatingViewModel()
    var body: some View {
        VStack {
            Spacer()
            PulsatingView(viewModel: model)
            Spacer()
            Button("Toggle") { self.model.colorIndex = Int.random(in: 0...2) }
        }
    }
}

struct TestPulseColorView_Previews: PreviewProvider {
    static var previews: some View {
        TestPulseColorView()
    }
}
...