Как оживить переход между представлениями в SwiftUI? - PullRequest
1 голос
/ 21 марта 2020

У меня следующий вид.

import SwiftUI

struct AppView: View {
    @EnvironmentObject var appStore: AppStore

    var body: some View {
        ZStack {
            Color.blue

            if .game == self.appStore.appMode {
                GameView()
            } else if .options == self.appStore.appMode {
                OptionsView()
            } else {
                MenuView()
            }
        }
    }
}

Я хочу анимировать переключение между дочерними видами. Я видел несколько примеров использования состояния для одного коммутатора, но я полагаюсь на более чем один. Я также попытался применить анимацию внутри дочернего представления с onAppear и onDisappear. Это работает, но когда представление не отображается, onDisappear больше не выполняется. Кроме того, я хотел бы, чтобы это работало для всех представлений.

Есть ли способ сделать это без использования нескольких состояний? Я хотел бы использовать только .transition и .animation.

. На данный момент мое лучшее решение - это.

import SwiftUI

struct AppView: View {
    @EnvironmentObject var appStore: AppStore

    var body: some View {
        ZStack {
            Color.blue

            if .game == self.appStore.appMode {
                GameView()
                .transition(.scale)
                .zIndex(1) // to keep the views on top, however this needs to be changed when the active child view changes.
            } else if .options == self.appStore.appMode {
                OptionsView()
                .transition(.scale)
                .zIndex(2)
            } else {
                MenuView()
                .transition(.scale)
                .zIndex(3)
            }
        }
    }
}

И на каждый переключатель смены вида.

.onTapGesture {
    withAnimation(.easeInOut(duration: 2)) {
        self.appStore.appMode = .game
    }
}

1 Ответ

2 голосов
/ 21 марта 2020

При следующем подходе вы можете изменить appMode, используя sh (onAppear, onTapGesture и т. Д. c.). Длительность анимации, конечно, может быть установлена ​​любой, какой вы будете sh (как и тип перехода, на самом деле, однако некоторые переходы ведут себя плохо в режиме предварительного просмотра и должны быть протестированы на симуляторе или реальном устройстве).

Демонстрация: (первый миг - просто предварительный запуск, затем два перехода для onAppear, затем для onTap)

demo

Протестировано с Xcode 11.4 / iOS 13.4 - работает и в Предпросмотре, и в Симуляторе.

Код: Важные части помечены комментариями, встроенными.

var body: some View {
    ZStack {
        // !! to keep background deepest, `cause it affects removing transition
        Color.blue.zIndex(-1)

        // !! keep any view in explicit own `if` (don't use `else`)
        if .game == self.appStore.appMode {
            GameView()
                .transition(AnyTransition.scale.animation(.easeInOut(duration: 1)))
        }

        if .options == self.appStore.appMode {
            OptionsView()
                .transition(AnyTransition.scale.animation(.easeInOut(duration: 1)))
        }

        if .menu == self.appStore.appMode {
            MenuView()
                .transition(AnyTransition.scale.animation(.easeInOut(duration: 1)))
        }
    }
}

Обновление: для .slide (и, возможно, другие движущиеся переходы) изменение состояния должно быть заключено в явное withAnimation, как показано ниже

withAnimation {
    self.appStore.appMode = new_mode_here
}

Примечание: это один из переходов, который не поддерживается Preview - test в Simulator .

Пример перехода типа

    ...
    if .menu == self.appStore.appMode {
        Text("MenuView").frame(width: 300, height: 100).background(Color.red)
            .transition(AnyTransition.move(edge: .bottom).combined(with: .opacity).animation(.easeInOut(duration: 1)))
    }
}
.onTapGesture {
    withAnimation {
        let next = self.appStore.appMode.rawValue + 1
        self.appStore.appMode = next > 2 ? .game : AppStore.AppMode(rawValue: next)!
    }
}

demo2

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...