【问题标题】:SwiftUI animation and subsequent reverse animation to original stateSwiftUI 动画和随后的反向动画到原始状态
【发布时间】:2020-05-23 12:17:48
【问题描述】:

我正在使用 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 上也找不到任何属性,它可以让我的动画自动恢复到原始状态(在第一个动画之后我不必与视图交互),我也没有找到任何关于如何确定第一个动画何时真正完成,以便能够触发新动画。

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

【问题讨论】:

    标签: ios swift animation swiftui


    【解决方案1】:

    这是一个基于ReversingScale 动画修饰符的解决方案,来自this my answer

    使用 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 } }
    【解决方案2】:

    如果您定义动画应该花费多长时间,另一种可行的方法:

    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()
                        }
                    }
            }
        }
    }
    

    【讨论】:

    • 这么好的解决方案。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-29
    • 1970-01-01
    • 1970-01-01
    • 2022-11-19
    • 2017-12-23
    • 2011-04-06
    相关资源
    最近更新 更多