SwiftUI: анимация переходов

Как анимировать переходы между слайдами между разными представлениями?

В следующем примере кода я создал средство выбора, которое выбирает, какое представление отображать, и моя цель — получить переход, похожий на переход 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)
        }
    }
}

2 ответа

Вам действительно нужен 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)
        }
    }

}

Чтобы получить нужную анимацию слайдов, .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)
            }
        }
    }
}
Другие вопросы по тегам