SwiftUI 视图在意想不到的路径上动画

SwiftUI view animates at unexpected path

我做了以下 PulsatingView:

struct PulsatingView: View {
    
    @State private var opacity = 0.7
    @State private var scale: CGFloat = 0.5

    var body: some View {
        VStack {
            ZStack {
                Circle()
                    .fill(Color.black.opacity(opacity))
                    .animation(.easeInOut(duration: 2).delay(1.5).repeatForever(autoreverses: false))
                    .frame(width: 7, height: 7)
                    .scaleEffect(scale)
                    .animation(.easeIn(duration: 2.5).delay(1).repeatForever(autoreverses: false))
                Circle()
                    .fill(Color.black)
                    .frame(width: 7, height: 7)
            }
        }
        .onAppear {
            opacity = 0
            scale = 5
        }
    }
}

它产生以下结果:(点击查看动画;它是一个 .gif)

但是,当我将它添加到视图中时,例如在 VStack 中,会发生这种情况:(点击查看动画;它是一个 .gif)

我不知道为什么会这样,也不知道该如何解决。我已经尝试过添加 .fixedSize(horizontal: true, vertical: true).frame(width: 50, height: 50) 等修饰符,但这没有帮助。

有人知道这是怎么回事吗?

尝试使用具有连接值的动画,例如

Circle()
    .fill(Color.black.opacity(opacity))
    .animation(.easeInOut(duration: 2).delay(1.5).repeatForever(autoreverses: false), value: opacity) // << here !!
    .frame(width: 7, height: 7)
    .scaleEffect(scale)
    .animation(.easeIn(duration: 2.5).delay(1).repeatForever(autoreverses: false), value: scale)    // << here !!

重要提示: 如果它在 NavigationView 中启动,则动画状态应被推迟激活。 .

中提供了原因和调查详情

这个问题与您的代码无关,因为我们应该使用 NavigationView 来修复它 DispatchQueue.main.async我也想重构您的代码,希望对您有所帮助,您也可以尽可能避免硬编码值,例如,您可以在视图外应用框架:

struct ContentView: View {
    
    var body: some View {
        
        CircleView(lineWidth: 0.5, color: .red, scale: 5.0)
            .frame(width: 7, height: 7)
        
    }
    
}




struct CircleView: View {

    let lineWidth: CGFloat
    let color: Color
    let scale: CGFloat
    
    @State private var startAnimation: Bool = Bool()
    
    var body: some View {
        
        Circle()
            .strokeBorder(style: .init(lineWidth: startAnimation ? .zero : lineWidth)).opacity(startAnimation ? .zero : 1.0)
            .scaleEffect(startAnimation ? scale : 1.0)
            .overlay( Circle() )
            .foregroundColor(color)
            .onAppear() { DispatchQueue.main.async { startAnimation.toggle() } }
            .animation(.easeIn(duration: 2.5).delay(1).repeatForever(autoreverses: false), value: startAnimation)
        
    }
}

我终于设法在我自己的项目中找到解决这个问题的方法 - 我发现让动画视图在 NavigationView 中工作的唯一解决方案是在 onAppear 调用中移动动画,像这样:

Circle()
    .fill(Color.black.opacity(opacity))
    .onAppear {
        withAnimation(.easeInOut(duration: 2).repeatForever(autoreverses: false)) {
            opacity = 0
        }
    }

希望这可以帮助其他人,如果他们遇到了我最终遇到的同样问题!