0

如何为不同视图之间的幻灯片过渡设置动画?

在下面的示例代码中,我创建了一个 Picker 来选择要显示的视图,我的目标是获得一个看起来类似于 NavigationLink 转换的转换。目前它根本没有动画。如果我将.animation(.easeInOut(duration: 2))修改器添加到ZStack它,它会使淡入淡出动画动画 2 秒,但我不明白为什么。

struct ContentView: View {

    enum WhichScreen: String, CaseIterable {
        case red, blue, green, yellow
    }

    @State private var whichScreen = WhichScreen.red

    var body: some View {
        VStack {
            Picker("screen", selection: $whichScreen.animation()) {
                ForEach(WhichScreen.allCases, id: \.self) { value in
                    Text(value.rawValue).tag(value)
                }
            }
            .pickerStyle(SegmentedPickerStyle())
            ZStack {
                Color.black
                switch whichScreen {
                case .red:
                    Color.red
                case .blue:
                    Color.blue
                case .green:
                    Color.green
                case .yellow:
                    Color.yellow
                }
            }
            .transition(.slide)
        }
    }
}
4

2 回答 2

1

要获得您正在寻找的幻灯片动画,.transition需要将其应用于您想要滑动的部分(例如,在这种情况下为非黑色):

ZStack {
    Color.black
    Group {
        switch whichScreen {
        case .red:
            Color.red
        case .blue:
            Color.blue
        case .green:
            Color.green
        case .yellow:
            Color.yellow
        }
    }.transition(.slide)
}

如果您希望它与转换完全一样,您仍然需要处理更多步骤NavigationLink,这就是现在,“旧”或“先前”视图在转换之前消失的事实。如果您希望将其包含在堆栈中,您可以执行以下操作:

struct ContentView: View {
    
    enum WhichScreen: String, CaseIterable {
        case red, blue, green, yellow
    }
    
    @State private var whichScreen = WhichScreen.red
    @State private var previousScreen : WhichScreen? = .none
    
    var body: some View {
        VStack {
            Picker("screen", selection: $whichScreen.animation()) {
                ForEach(WhichScreen.allCases, id: \.self) { value in
                    Text(value.rawValue).tag(value)
                }
            }
            .pickerStyle(SegmentedPickerStyle())
            .onChange(of: whichScreen) { [whichScreen] _ in
                previousScreen = whichScreen
            }
            ZStack {
                Color.black
                if let previousScreen = previousScreen {
                    switch(previousScreen) {
                    case .red:
                        Color.red
                    case .blue:
                        Color.blue
                    case .green:
                        Color.green
                    case .yellow:
                        Color.yellow
                    }
                    
                }
                Group {
                    switch whichScreen {
                    case .red:
                        Color.red
                    case .blue:
                        Color.blue
                    case .green:
                        Color.green
                    case .yellow:
                        Color.yellow
                    }
                }.transition(.slide)
            }
        }
    }
}
于 2021-07-15T22:52:53.407 回答
1

你真的需要黑色的 ZStack(在你的示例代码段中永远不可见)吗?没有它,转换开箱即用(在模拟器中,而不是在 SwiftUI 预览中):

struct ContentView: View {

    enum WhichScreen: String, CaseIterable {
        case red, blue, green, yellow
    }

    @State private var whichScreen = WhichScreen.red

    var body: some View {
        VStack {
            Picker("screen", selection: $whichScreen.animation()) {
                ForEach(WhichScreen.allCases, id: \.self) { value in
                    Text(value.rawValue).tag(value)
                }
            }
            .pickerStyle(SegmentedPickerStyle())
            Group {
                switch whichScreen {
                case .red:
                    Color.red
                case .blue:
                    Color.blue
                case .green:
                    Color.green
                case .yellow:
                    Color.yellow
                }
            }
            .transition(.slide)
        }
    }

}
于 2021-07-16T14:27:02.213 回答