【问题标题】:Triggering an animation when a boolean is true当布尔值为真时触发动画
【发布时间】:2021-02-19 19:33:21
【问题描述】:

我想制作一个像这样的动画:一个带有视图的 ZStack,上面是一个紫色矩形,最初的比例为 0,不透明度为 0,位于屏幕的中心。

当动画被触发时,会发生两个动画:

  1. 矩形的比例在 0.4 秒内从 0 增加到 1。
  2. 矩形的不透明度在 0.3 秒内从 0 增加到 1,在 0.1 秒内从 1 增加到 0。

这是我试图这样做:

struct ContentView : View {

  @State private var scale: CGFloat = 0
  @State private var scaleSeed: CGFloat = 0.1
  @State private var counter: Int = 1
  @State private var triggerFlashAnimation = false {
    didSet {
      scale = 0
      counter = 1
    }
  }


  var body: some View {
    
    ZStack {
      Text("Hello")

      if triggerFlashAnimation {
        Rectangle()
          .background(Color.purple)
          .scaleEffect(scale)
          .onAppear {
            scale += scaleSeed
            counter += 1
          }
      }
}

我认为这会为比例设置动画,但这非常粗糙,因为我无法控制时间。

我记得在 CoreGraphics 时代,您可以为时间和值定义关键帧。

如何使用 SwiftUI 做到这一点。我的意思是为每个参数定义关键帧和值的精确动画?

我四处搜索,一无所获。

【问题讨论】:

  • 我认为 SwiftUI 不支持关键帧动画。

标签: swiftui


【解决方案1】:

SwiftUI 不支持我们在 CoreAnimation 中习惯使用的关键帧(来源:https://stackoverflow.com/a/56908148/560942https://swiftui-lab.com/swiftui-animations-part1/)。

但是,您可以使用delay 对链接进行变体:

struct ContentView : View {
    
    @State private var scale: CGFloat = 0
    @State private var opacity: Double = 0
    @State private var triggerFlashAnimation = false
    
    func triggerAnimationActions() {
        withAnimation(.linear(duration: 0.4)) {
            scale = 1
        }
        withAnimation(.linear(duration: 0.3)) {
            opacity = 1
        }
        withAnimation(Animation.linear(duration: 0.1).delay(0.3)) {
            opacity = 0
        }
        
        // reset
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) {
            triggerFlashAnimation = false
            scale = 0
            opacity = 0
        }
    }
    
    var body: some View {
        ZStack {
            Text("Hello")
            
            Button(action: { triggerFlashAnimation = true }) {
                Text("Button")
            }.onChange(of: triggerFlashAnimation) { (val) in
                if val {
                    triggerAnimationActions()
                }
            }
            
            if triggerFlashAnimation {
                Rectangle()
                    .fill(Color.purple.opacity(opacity))
                    .frame(width: 100, height: 100)
                    .scaleEffect(scale)
            }
            
        }.frame(maxWidth: .infinity, maxHeight: .infinity)
    }
}

可能还值得研究 AnimatableModifier ,它允许您定义一个 animatableData 属性,您可以在其中插入值、基于动画的特定状态的精确帧等,但据我所知,不考虑完全用于计时——它只是让您根据当前动画的精确值设置状态。阅读有关AnimatableModifier 的好资源:https://www.hackingwithswift.com/quick-start/swiftui/how-to-animate-the-size-of-text

【讨论】:

    猜你喜欢
    • 2014-10-22
    • 2016-06-20
    • 2016-10-13
    • 2020-10-06
    • 1970-01-01
    • 1970-01-01
    • 2022-10-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多