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

时间:2019-09-04 00:13:20

标签: ios swift xcode 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()
    }
}

显然,这种方法失败了,因为SwiftUI视图需要不透明的返回类型some View。可以使用AnyView包装器类型来缓解这种情况(尽管有点怪异),该包装器提供了类型擦除功能,并将允许以下代码进行编译。

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())
    }
}

是否存在不需要使用AnyView的更正确的方法? SceneDelegate中是否有功能可以处理向完全不同的视图层次结构的过渡?

2 个答案:

答案 0 :(得分:3)

执行此类操作的最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()
    }
}

要注意的最重要的一点是,这样一来,您就不会依赖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()
    }
}

答案 1 :(得分:-1)

我将提取将哪个视图呈现给函数的逻辑:

struct ContentView: View {

    @State var applicationState = getApplicationState()

    var body: some View {
        content()
    }

    func content() -> AnyView {
        guard applicationState.hasSeenOnboarding else {
            return AnyView(OnBoarding())
        }

        guard applicationState.isSignedIn else {
            return AnyView(Registration())
        }

        return AnyView(MainContent())
    }
}