SwiftUI动画及其反向动画返回原始状态

8

我正在使用SwiftUI,在应用程序中展示演示目的时,我希望在视图出现时立即对其进行动画处理(动画的具体类型并不重要)。 假设我只想将视图放大然后缩小到其原始大小,我需要能够将视图动画处理到一个新状态,然后立即返回到原始状态。 以下是目前为止我尝试过的示例代码:

import SwiftUI
import Combine

struct ContentView: View {
    @State private var shouldAnimate = false
    private var scalingFactor: CGFloat = 2    

    var body: some View {
        Text("hello world")
        .scaleEffect(self.shouldAnimate ? self.scalingFactor : 1)
        .onAppear {
            let animation = Animation.spring().repeatCount(1, autoreverses: true)
            withAnimation(animation) {
                self.shouldAnimate.toggle()
            }
        }
    }

显然,这并不能完全满足我的要求,因为 let animation = Animation.spring().repeatCount(1, autoreverses: true) 仅通过平滑的autoreverse=true设置来确保动画(到新状态)被重复,但仍会导致视图在最终状态下按比例缩小至scalingFactor

因此,我既找不到animation上让我自动将动画反转回原始状态的属性(而无需在第一次动画之后与视图进行交互),也没有找到任何确定第一个动画实际完成以便能够触发新动画的方法。

我认为在某些View出现时对其进行动画处理非常普遍,例如仅仅展示该View可以进行交互,但最终不改变View的状态。例如,在按钮上动画弹跳效果,最终将按钮设置回其原始状态。当然,我找到了几种解决方案,建议与按钮交互以触发反向动画回到其原始状态,但这不是我要寻找的东西。

2个回答

9

如果你定义了动画应该持续的时间,另一种途径就是使用以下方法:

struct ContentView: View {
    @State private var shouldAnimate = false
    private var scalingFactor: CGFloat = 2

    var body: some View {
        Text("hello world")
            .scaleEffect(self.shouldAnimate ? self.scalingFactor : 1)
            .onAppear {
                let animation = Animation.easeInOut(duration: 2).repeatCount(1, autoreverses: true)
                withAnimation(animation) {
                    self.shouldAnimate.toggle()
                }
                DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
                    withAnimation(animation) {
                        self.shouldAnimate.toggle()
                    }
                }
        }
    }
}

1
这是一个非常好的解决方案。非常感谢。 - Badrinath
好的解决方案。简单易懂,能够完成任务。 - NSSpeedForce

8

以下是基于可动画修改器 ReversingScale 的解决方案,参考我的答案

更新:Xcode 13.4 / iOS 15.5

演示效果

这里有完整的测试模块

在 Xcode 11.4 / iOS 13.4 上进行了测试

演示效果

struct DemoReverseAnimation: View {
    @State var scalingFactor: CGFloat = 1

    var body: some View {
        Text("hello world")
        .modifier(ReversingScale(to: scalingFactor, onEnded: {
            DispatchQueue.main.async {
                self.scalingFactor = 1
            }
        }))
        .animation(.default)
        .onAppear {
            self.scalingFactor = 2
        }
    }
}

在此基础上,如果想要一个平滑的反向动画,我们可以将 self.scalingFactor = 1 包装在 withAnimation 块中:DispatchQueue.main.async { withAnimation { self.scalingFactor = 1 } } - Alienbash

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接