在 SwiftUI 视图中使用开关/枚举

Ral*_*ert 1 swiftui

从 Xcode 11.4 开始,SwiftUI 不允许switch在 Function builder 块中使用语句,如VStack {},失败并出现一般错误,如Generic parameter 'Content' could not be inferred. 如何switch在 SwiftUI 中使用该语句根据枚举值创建不同的视图?

Ral*_*ert 8

switch 自 Xcode 12 起支持在 SwiftUI 视图构建器中:

enum Status {
    case loggedIn, loggedOut, expired
}

struct SwiftUISwitchView: View {

    @State var userStatus: Status = .loggedIn

    var body: some View {
        VStack {
            switch self.userStatus {
            case .loggedIn:
                Text("Welcome!")
            case .loggedOut:
                Image(systemName: "person.fill")
            case .expired:
                Text("Session expired")
            }

        }
    }
}

Run Code Online (Sandbox Code Playgroud)

对于 Xcode 11,您可以使用以下解决方法:

a) 将其包装在Group具有显式返回类型的单个块中 - 如果 switch 语句是函数构建器块中的唯一语句,则允许这样做:

enum Status {
    case loggedIn, loggedOut, expired
}

struct SwiftUISwitchView: View {

    @State var userStatus: Status = .loggedIn

    var body: some View {
        VStack {
            Group { () -> Text in
                switch(self.userStatus) {
                case .loggedIn:
                    return Text("Welcome!")
                case .loggedOut:
                    return Text("Please log in")
                case .expired:
                    return Text("Session expired")
                }
            }
        }
    }
}

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

备选方案 b) 创建一个单独的函数来根据枚举计算视图:

struct SwiftUISwitchView: View {

    @State var userStatus: Status = .loggedIn

    // if it's always the same View, you can use some View
    func viewFor(status: Status) -> some View {
        switch(status) {
        case .loggedIn:
            return Text("Welcome!")
        case .loggedOut:
            return Text("Please log in")
        case .expired:
            return Text("Session expired")
        }
    }

    var body: some View {
        VStack {
            viewFor(status: userStatus)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果返回的视图可以有不同的类型,则需要将其包装在 an 中,AnyView因为some View要求返回类型在所有情况下都相同:

// if it's different types, you have to erase to AnyView
func viewForStatusDifferentViews(status: Status) -> AnyView {
    switch(status) {
    case .loggedIn:
        return AnyView(Text("Welcome!"))
    case .loggedOut:
        return AnyView(Image(systemName: "person.fill"))
    case .expired:
        return AnyView(Text("Session expired"))
    }
}
Run Code Online (Sandbox Code Playgroud)

替代方法 c) 创建一个单独的 View 以通过枚举值计算 View:

// if it's different types, you have to erase to AnyView
func viewForStatusDifferentViews(status: Status) -> AnyView {
    switch(status) {
    case .loggedIn:
        return AnyView(Text("Welcome!"))
    case .loggedOut:
        return AnyView(Image(systemName: "person.fill"))
    case .expired:
        return AnyView(Text("Session expired"))
    }
}
Run Code Online (Sandbox Code Playgroud)

Github 上的可运​​行示例代码:SwiftUIPlayground