【问题标题】:SwiftUI animation freeze on first displaySwiftUI 动画在第一次显示时冻结
【发布时间】:2022-10-20 15:59:59
【问题描述】:

我正在编写我的第一个 SwiftUI 应用程序,我想在文本上创建一个动画(以慢慢显示和隐藏此文本)。这是我的代码:

import SwiftUI

struct TrendLabel: View {
    let trendType: String
    
    @State private var animationAmount = 0.0
    
    var body: some View {
        HStack {
            if(trendType != "aucune"){
                Label(trendType, systemImage: "arrow.down.right")
                    .foregroundColor(trendType == "hausse" ? .red : .green)
                    .opacity(2 - animationAmount)
                    .animation(
                        .easeOut(duration: 1).delay(1).repeatForever(autoreverses: true),
                        value: animationAmount
                    )
            }
        }
        .onAppear {
            animationAmount = 1.6
        }
    }
}

struct TrendLabel_Previews: PreviewProvider {
    static var previews: some View {
        TrendLabel(trendType: "hausse")
    }
}

但它似乎不起作用,因为我的文本以最小不透明度值 (here is a screenshot of the result) 冻结。

有人知道如何解决这个问题吗?

【问题讨论】:

    标签: swift animation swiftui


    【解决方案1】:

    欢迎来到 StackOverflow!你的动画有几个问题。

    1. 要为不透明度设置动画,您需要一个Bool 值,或者一个可以计算为Bool 值的表达式。然后,您使用三元组来做出决定。
    2. .opacity() 值必须介于 0 和 1 之间。

      您的代码应该是:

      struct TrendLabel: View {
          let trendType: String
          
          @State private var animate = false
          @Binding var animationAmount: Double
          
          var body: some View {
              HStack {
                  if(trendType != "aucune"){
                      Label(trendType, systemImage: "arrow.down.right")
                          .foregroundColor(trendType == "hausse" ? .red : .green)
                          .opacity(animate ? animationAmount : 1)
                          .animation(
                              .easeOut(duration: 1).delay(1).repeatForever(autoreverses: true),
                              value: animate
                          )
                  }
              }
              .onAppear {
                  DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                      animationAmount = 0.4
                      animate = true
                  }
              }
          }
      }
      

      您还可以更改不透明度中间动画,更改将立即反映。

    【讨论】:

    • 您好,感谢您的帮助!我刚刚尝试过,但标签在出现时以最小不透明度值冻结。但是一旦我重新启动应用程序,动画效果就会很好。你知道有什么问题吗?
    • 你能详细说明你是如何尝试的吗?这是一个更大的应用程序的一部分,还是你只是尝试在它自己的应用程序中运行这个视图?
    • 我不确定这是不是。您的问题,但我对其进行了更新以解决从.onppear 启动动画时可能出现的问题。让我知道这是否可以解决问题。
    • 我有一段时间有类似的问题。我也在使用延迟,但感觉我们缺少一些“onNavigationEnd”回调。在我的情况下,动画列表会导致应用程序冻结(一些无限循环,可以看到内存攀升)并最终崩溃。感觉onAppear 应该在与viewDidAppearUIKit 上调用的类似状态下调用。
    【解决方案2】:

    基于@Yrb's answer,您可以创建一个修饰符:

    struct DelayedAppear: ViewModifier {
        
        let delay: TimeInterval
        let callback: () -> Void
        
        func body(content: Content) -> some View {
            content
                .onAppear {
                    DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
                        callback()
                    }
                }
        }
    }
    
    extension View {
        func onAppear(after: TimeInterval, perform: @escaping () -> Void) -> some View {
            modifier(DelayedAppear(delay: after, callback: perform))
        }
    }
    

    用法:

    HStack {
     ...            
    }
    .onAppear(after: 0.5) {
        animationAmount = 0.4
        animate = true
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-02-07
      • 2014-12-16
      • 1970-01-01
      • 1970-01-01
      • 2017-07-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多