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

Posted

技术标签:

【中文标题】SwiftUI 视图以意想不到的路径动画【英文标题】:SwiftUI view animates at unexpected path 【发布时间】:2021-10-05 09:57:19 【问题描述】:

我做了以下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) 之类的修饰符,但这无济于事。

有人知道怎么回事吗?

【问题讨论】:

嗨@LinusGeffarth,我现在也有同样的问题。你找到解决办法了吗?我尝试了DispatchQueue.main.async ,但这没有用。还在挣扎。任何帮助将不胜感激,谢谢! 看来您已经找到了解决方案。对我来说,Asperi 的回答起到了作用(这就是我接受它的原因)。 是的,一切都很好,谢谢你回复我:) 【参考方案1】:

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

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 启动的,那么动画状态应该被推迟激活。原因及调查详情见https://***.com/a/66643096/12299030。

【讨论】:

确实是NavigationView!我试过你的代码,但问题仍然存在...... 那么你需要像上面提供的第一个链接一样延迟动画开始。 啊哈!谢谢,第二个链接解决了我的问题。如果您在此处更新答案,我会将其标记为已接受。【参考方案2】:

这个问题与你的代码无关,因为 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)
        
    

【讨论】:

【参考方案3】:

我终于设法在我自己的项目中找到了解决方案 - 我发现让动画视图在 NavigationView 中工作的唯一解决方案是将动画移动到 onAppear 调用中,如下所示:

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

希望这可以帮助其他人,如果他们被困在我最终遇到的同一问题上!

【讨论】:

以上是关于SwiftUI 视图以意想不到的路径动画的主要内容,如果未能解决你的问题,请参考以下文章

Swiftui 动态动画面板从下到上

Ios Swift 在非线性路径中动画视图

ScrollView 的 SwiftUI 动画

SwiftUI NavigationLink 在范围内找不到“json”

嵌入另一个视图时,SwiftUI 动画不起作用

如何在 SwiftUI 中禁用位置动画?