首页 > 解决方案 > SwiftUI 同步多个带有延迟的 SwiftUI 动画

问题描述

我正在尝试构建一个包含多个项目的视图,这些项目应该彼此同步动画;例如,如果一项为 25%,则其他三项应为 50%、75% 和 100%。

刚开始使用的幼稚选项.delay(delay)似乎可以完美地工作,但是一旦我切换应用程序,不同的动画都会被重置为完全偏移(不再有任何偏移)。我尝试了许多 hacky 解决方法,包括:

请注意,我根本没有投资于这个特定的解决方案。任何有关解决此问题的更好方法的建议都非常受欢迎。

切换应用程序之前 切换应用程序后
前 在此处输入图像描述

struct MyRepeatingItemView: View {
    var delay: Double
    
    @State
    var isTranslated = false
    
    var body: some View {
        Color.red
            .opacity(0.2)
            .frame(width: 256, height: 256)
            .scaleEffect(isTranslated ? 1 : 0.01)
            .onAppear {
                withAnimation(Animation.linear(duration: 4).repeatForever(autoreverses: false).delay(delay)) {
                    isTranslated.toggle()
                }
            }
    }
}

struct MyRepeatingContainerView: View {
    
    var body: some View {
        ZStack {
            Color.blue
                .frame(width: 256, height: 2)
            Color.blue
                .frame(width: 2, height: 256)
            MyRepeatingItemView(delay: 0.0)
            MyRepeatingItemView(delay: 1.0)
            MyRepeatingItemView(delay: 2.0)
            MyRepeatingItemView(delay: 3.0)
        }
    }
}

标签: animationswiftui

解决方案


不同步视图的修复方法是将它们全部放在一个视图中,并且该视图会同时同步所有内容。我花了一些时间来制定模式,但这里是:

struct MyRepeatingItemView: View {
    
    @State var isTranslated = false
    
    var body: some View {
        ZStack {
            Rectangle()
                .fill(Color.red)
                .frame(width: 256, height: 256)
                .opacity(isTranslated ? 0 : 0.25)
                .scaleEffect(isTranslated ? 1 : 0.75)
            Rectangle()
                .fill(Color.red)
                .frame(width: 256, height: 256)
                .opacity(0.25)
                .scaleEffect(isTranslated ? 0.75 : 0.5)
            Rectangle()
                .fill(Color.red)
                .frame(width: 256, height: 256)
                .opacity(0.25)
                .scaleEffect(isTranslated ? 0.5 : 0.25)
            Rectangle()
                .fill(Color.red)
                .frame(width: 256, height: 256)
                .opacity(0.25)
                .scaleEffect(isTranslated ? 0.25 : 0)
        }
        .onAppear {
            withAnimation(Animation.linear(duration: 1).repeatForever(autoreverses: false)) {
                isTranslated.toggle()
            }
        }
    }
}

struct MyRepeatingContainerView: View {
    
    var body: some View {
        ZStack {
            Color.blue
                .frame(width: 256, height: 2)
            Color.blue
                .frame(width: 2, height: 256)
            
            MyRepeatingItemView()
        }
    }
}

推荐阅读