SwiftUI .onAppear withAnimation ускоряется каждый раз, когда появляется представление. Почему?

В моем приложении есть постоянные анимации, которые запускаются onAppear и настроен с помощью withAnimation, обновляя @State свойство.

Каждый раз, когда появляется представление, анимация выполняется немного быстрее, чем раньше, поэтому, если представление отображается, затем закрывается модальным дисплеем или скрывается в навигации, а затем снова появляется, анимация начинает идти очень, очень быстро - может быть, 10 или 20 раз быстрее, чем следовало бы.

Вот код ...

      struct HueRotationAnimation: ViewModifier {
    @State var hueRotationValue: Double
    func body(content: Content) -> some View {
        content
            .hueRotation(Angle(degrees: hueRotationValue))
            .onAppear() {
                DispatchQueue.main.async {
                    withAnimation(.linear(duration: 20).repeatForever(autoreverses: false)) {
                        hueRotationValue += 360
                    }
                }
            }
    }
}

struct GradientCircle: View {
    var gradient: Gradient
    @State var hueRotationValue: Double = Double.random(in: 0..<360)
    
    var body: some View {
        GeometryReader { geometry in
            Circle()
                .fill(
                    radialGradient(geometry: geometry, gradient: gradient)
                )
                .modifier(HueRotationAnimation(hueRotationValue: hueRotationValue))
        }
    }
}

func radialGradient(geometry: GeometryProxy, gradient: Gradient) -> RadialGradient {
    RadialGradient(gradient: gradient,
                   center: .init(x: 0.82, y: 0.85),
                   startRadius: 0.0,
                   endRadius: max(geometry.size.width, geometry.size.height) * 0.8)
}

Есть идеи, что вызывает это ускорение каждый раз, когда представление снова появляется? Есть предложения по решению этой проблемы?

(Примечание: это работает под управлением Xcode 13.0 beta 4)

2 ответа

Решение

Я думаю, это связано с вашим += 360, потому что каждый раз, когда он появляется, количество градусов, на которое он должен повернуться, увеличивается еще на 360 градусов. Вместо того, чтобы добавлять 360 в экран, попробуйте установить логическое состояние, когда должна запускаться анимация. Попробуйте приведенный ниже код и посмотрите, работает ли он для вас.

      struct HueRotationAnimation: ViewModifier {
@State var hueRotationValue: Double
@State private var animated = false

func body(content: Content) -> some View {
    content
        .hueRotation(Angle(degrees: animated ? hueRotationValue : hueRotationValue + 360)).animation(.linear(duration: 20).repeatForever(autoreverses: false))
        .onAppear() {
            self.animated.toggle()
        }
}
}

Таким образом, 360-градусная анимация должна оставаться на 360 градусов, а скорость анимации не должна меняться.

Чтобы продвинуться, ответ @yawnobleix, я добавил переключатель .onDisappear. Он устраняет некоторые другие ошибки, когда представление появляется> исчезает> появляется.

      struct HueRotationAnimation: ViewModifier {
    @State var hueRotationValue: Double
    @State private var animated = false
    func body(content: Content) -> some View {
        content
            .hueRotation(Angle(degrees: animated ? hueRotationValue : hueRotationValue + 360)).animation(.linear(duration: 20).repeatForever(autoreverses: false))
            .onAppear {
                animated = true
            }
            .onDisappear {
                animated = false
            }
    }
}
Другие вопросы по тегам