SwiftUI 动画和随后的反向动画到原始状态

Ali*_*ash 5 animation ios swift swiftui

我正在使用 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()
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

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

所以我也找不到任何animation可以让我的动画自动反转回原始状态的属性(在第一个动画之后我不必与视图交互),我也没有找到任何关于如何确定第一个动画的时间居然完成了,才能触发新的动画。

我发现在某些视图的外观上设置动画是很常见的做法,例如只是为了展示该视图可以与之交互,但最终不会改变视图的状态。例如,为按钮上的反弹效果设置动画,最终将按钮设置回其原始状态。当然,我找到了几种建议与按钮交互以触发反向动画返回其原始状态的解决方案,但这不是我想要的。

Kuh*_*ann 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()
                    }
                }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Asp*_*eri 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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)