SwiftUI如何拥有下一个和后一个动画?

问题描述

我制作了具有3页和“下一步”,“返回”按钮的示例应用程序。

enter image description here

当我单击“下一步”时,动画是完美的:旧内容在左边,新内容在右边。

但是,我正在努力使“后退”动画同时运行。

目标:单击“返回”时,旧内容应移至右侧,新内容应从左侧移出。 (“后退”的动画应与“下一个”的动画相反)

有什么想法要实现吗?

以下是“下一个”的完美过渡

struct ContentView: View {
    @State var page: Int = 0
    
    var body: some View {
        
        vstack {
            HStack {
                Button(action: { withAnimation() { self.page = self.page - 1 } }) {
                    Text("Back")
                }
                
                Spacer()
                
                Button(action: { withAnimation() { self.page = self.page + 1 }}) {
                    Text("Next")
                }
            }
            Spacer()
            
            if page == 0 {
                PageView(name: "First page",color: .brown)
                    .transition(AnyTransition.asymmetric(insertion: .move(edge: .trailing),removal: .move(edge: .leading)))
            } else if page == 1 {
                PageView(name: "Second page",color: .systemGreen)
                    .transition(AnyTransition.asymmetric(insertion: .move(edge: .trailing),removal: .move(edge: .leading)))
            } else if page == 2 {
                PageView(name: "Third page",color: .systemBlue)
                    .transition(AnyTransition.asymmetric(insertion: .move(edge: .trailing),removal: .move(edge: .leading)))
            }
        }
    }
}

struct PageView: View {
    var name: String
    var color: UIColor
    var body: some View {
        HStack {
            Spacer()
            Text(name)
            Spacer()
        }
        .padding()
        .padding(.vertical,50)
        .background(Color(color))
    }
}

解决方法

向后导航时,您需要反向转换。

这是可行的方法(也可以在一个位置进行过渡,并且校正后的动画可以在任何地方工作,包括预览)。

通过Xcode 12 / iOS 14测试。

demo

struct ContentView: View {
    @State var page: Int = 0

    @State private var isBack = false   // << reverse flag (not animatable)
    var body: some View {

        VStack {
            HStack {
                Button(action: {
                    self.isBack = true
                    self.page = self.page - 1
                }) {
                    Text("Back")
                }

                Spacer()

                Button(action: {
                    self.isBack = false
                    self.page = self.page + 1
                }) {
                    Text("Next")
                }
            }
            Spacer()

            Group {
                if page == 0 {
                    PageView(name: "First page",color: .brown)
                } else if page == 1 {
                    PageView(name: "Second page",color: .systemGreen)
                } else if page == 2 {
                    PageView(name: "Third page",color: .systemBlue)
                }
            }.transition(AnyTransition.asymmetric(
                insertion:.move(edge: isBack ? .leading : .trailing),removal: .move(edge: isBack ? .trailing : .leading))
            )
            .animation(.default,value: self.page)   // << animate here by value
        }
    }
}