每次视图出现时,SwiftUI .onAppear withAnimation 都会加快速度。为啥?

Posted

技术标签:

【中文标题】每次视图出现时,SwiftUI .onAppear withAnimation 都会加快速度。为啥?【英文标题】:SwiftUI .onAppear withAnimation speeds up each time the view appears. Why?每次视图出现时,SwiftUI .onAppear withAnimation 都会加快速度。为什么? 【发布时间】:2021-08-03 04:10:29 【问题描述】:

我的应用中有在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)

【问题讨论】:

【参考方案1】:

我认为这与您的 += 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 度并且动画的速度不应该改变。

【讨论】:

出色的解释和优雅的解决方案。谢谢。【参考方案2】:

为了推进,@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
            
    

【讨论】:

以上是关于每次视图出现时,SwiftUI .onAppear withAnimation 都会加快速度。为啥?的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI onAppear:动画持续时间被忽略

你可以在消失时为 SwiftUI 视图设置动画吗?

在 SwiftUI 中使用 onAppear 时出现无限循环

如何阻止视图在 SwiftUI 中出现动画?

在 SwiftUI 视图中结合 onChange 和 onAppear 事件?

iOS14.2 SwiftUI PageTabView 会多次调用 ChildView onAppear 方法