使用 SwiftUI 在不同的 UI 层次结构之间切换的正确方法是什么?

Rob*_*ert 5 xcode ios swift swiftui

想象一个典型的应用程序,它具有入门、登录/注册和某种内容。当应用程序加载时,您需要决定显示哪个视图。一个简单的实现可能是这样的:

struct ContentView: View {
    //assuming some centralized state that keeps track of basic user activity
    @State var applicationState = getApplicationState()

    var body: some View {

        if !applicationState.hasSeenOnboarding {
            return OnBoarding()
        }

        if !applicationState.isSignedIn {
            return Registration()
        }

        return MainContent()
    }
}
Run Code Online (Sandbox Code Playgroud)

显然,这种方法失败了,因为 SwiftUI 视图需要不透明的some View. 这可以通过使用AnyView包装器类型来缓解(尽管是hackishly),它提供类型擦除并允许下面的代码编译。

struct ContentView: View {
    //assuming some centralized state that keeps track of basic user activity
    @State var applicationState = getApplicationState()

    var body: some View {

        if !applicationState.hasSeenOnboarding {
            return AnyView(OnBoarding())
        }

        if !applicationState.isSignedIn {
            return AnyView(Registration())
        }

        return AnyView(MainContent())
    }
}
Run Code Online (Sandbox Code Playgroud)

是否有更正确的方法不需要使用AnyView?是否有SceneDelegate可以处理到完全不同的视图层次结构的转换的功能?

sup*_*cio 5

SwiftUI做这些事情的最-y 方法可能是使用Group视图:

import SwiftUI

struct ContentView: View {
    @State private var applicationState = getApplicationState()

    var body: some View {
        Group {
            if !applicationState.hasSeenOnboarding {
                OnBoarding()
            } else if !applicationState.isSignedIn {
                Registration()
            } else {
                MainContent()
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
Run Code Online (Sandbox Code Playgroud)

需要注意的最重要的一点是,通过这种方式,您将不会依赖于类型擦除AnyView(如果不是绝对必要的话,可以避免)。

如果您想在方法中封装初始视图创建,请不要使用类型擦除。相反,使用some关键字:

import SwiftUI

struct ContentView: View {
    @State private var applicationState = getApplicationState()

    private func initialView() -> some View {
        if !applicationState.hasSeenOnboarding {
            OnBoarding()
        } else if !applicationState.isSignedIn {
            Registration()
        } else {
            MainContent()
        }
    }

    var body: some View {
        initialView()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
Run Code Online (Sandbox Code Playgroud)