swift - 随着时间的推移,重复的 SwiftUI 动画变得不稳定

标签 swift animation swiftui

我开发了一个重复动画,开始时非常流畅,但在 10 或 20 秒后开始变得非常不稳定,我在设备上什么都不做。这是 View 的完整代码(它被设置为单 View 应用程序的内容 View ):

import SwiftUI

struct MovingCirclesView: View {
    @State var animationPercent: Double = 0

    var body: some View {
        ZStack {
            MovingCircle(animationPercent: $animationPercent, size: 300, movementRadius: 100, startAngle: 0)
                .offset(x: -200, y: -200)

            MovingCircle(animationPercent: $animationPercent, size: 400, movementRadius: 120, startAngle: .pi * 3/4)
                .offset(x: 50, y: 300)

            MovingCircle(animationPercent: $animationPercent, size: 350, movementRadius: 200, startAngle: .pi * 5/4)
                .offset(x: 10, y: 30)

            MovingCircle(animationPercent: $animationPercent, size: 230, movementRadius: 80, startAngle: .pi * 1/2)
                .offset(x: 220, y: -300)

            MovingCircle(animationPercent: $animationPercent, size: 230, movementRadius: 150, startAngle: .pi)
                .offset(x: 220, y: 100)
        }.frame(maxWidth: .infinity, maxHeight: .infinity)
            .animation(Animation.linear(duration: 30).repeatForever(autoreverses: false))
            .onAppear() { self.animationPercent = 1 }
    }

    private struct MovingCircle: View, Animatable {
        @Binding var animationPercent: Double

        let size: CGFloat
        let movementRadius: CGFloat
        let startAngle: Double

        var body: some View {
            Circle()
                .frame(width: size, height: size)
                .foregroundColor(Color.white)
                .opacity(0.1)
                .offset(angle: .radians(.pi * 2 * self.animationPercent + self.startAngle), radius: self.movementRadius)
        }
    }
}

struct MovingCirclesView_Previews: PreviewProvider {
    static var previews: some View {
        MovingCirclesView()
            .background(Color.black)
            .edgesIgnoringSafeArea(.all)
    }
}

struct AngularOffset: AnimatableModifier {
    var angle: Angle
    var radius: CGFloat

    var animatableData: AnimatablePair<Double, CGFloat> {
        get {
            return AnimatablePair(angle.radians, radius)
        }
        set {
            self.angle = .radians(newValue.first)
            self.radius = newValue.second
        }
    }

    func body(content: Content) -> some View {
        return content.offset(CGSize(
            width: CGFloat(cos(self.angle.radians)) * self.radius,
            height: CGFloat(sin(self.angle.radians)) * self.radius
        ))
    }
}
extension View {
    func offset(angle: Angle, radius: CGFloat) -> some View {
        ModifiedContent(content: self, modifier: AngularOffset(angle: angle, radius: radius))
    }
}

大意是有一串半透明的圆圈在慢慢地转圈圈。我担心这不值得消耗能量,并且无论如何都打算进行剖析,但令我惊讶的是,动画似乎很快就停滞不前了。我在 iPhone X 上对其进行分析,随着动画变得越来越不稳定,我没有看到 CPU 使用率和内存使用率随着时间的推移而增加。

有谁知道为什么动画会变得不稳定?我能做些什么来解决这个问题,还是我必须放弃这个想法?

最佳答案

更新:Xcode 13.4/iOS 15.5

现在看来 drawingGroup 没有像以前那样积极的效果,因为使用过的 .animation(.., value:) 动画可以正常工作并且资源消耗低。

demo

Test module on GitHub

原创

这是一个解决方案 - 通过使用 .drawingGroup 和显式动画激活 Metal。

适用于 Xcode 11.4/iOS 13.4 - 测试时间为 5 分钟,CPU 负载为 4-5%

ZStack {

   // ..  circles here

}.frame(maxWidth: .infinity, maxHeight: .infinity)
.drawingGroup()
.onAppear() {
    withAnimation(Animation.linear(duration: 30).repeatForever(autoreverses: false)) {
        self.animationPercent = 1
    }
}

注意:调查结果 - 在这种情况下,隐式动画似乎一次又一次地重新创建更新堆栈,因此它们成倍增加,但显式动画仅激活一次。

关于swift - 随着时间的推移,重复的 SwiftUI 动画变得不稳定,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62209277/

相关文章:

ios - 从应用内购买中获取付款信息

ios - 类 AVPlayer 的实例已被释放,而键值观察者仍向其注册

ios - 如何将值从一个 View 传递到 iOS 中的另一个 View ?

css - 从左到右动画 SVG 填充

ios - ScrollView 内容未填充 SwiftUI

swift - 属性包装器和 SwiftUI 环境 : how can a property wrapper access the environment of its enclosing object?

ios - 测试与非测试中的 Swift 和 CoreData 转换问题

ios - Shazam 应用程序像加载屏幕

iphone - 多个动画相继出现

ios - 如何在 SwiftUI 中通过点击手势制作放大缩小按钮动画?