从Xcode11.4开始,SwiftUI不允许在像VStack {}这样的函数构造器块中使用switch语句,失败时会出现像Generic parameter 'Content' could not be inferred这样的通用错误。如何在SwiftUI中使用switch语句根据枚举值创建不同的视图?
发布于 2020-05-17 00:07:19
从Xcode12开始支持SwiftUI视图构建器中的switch:
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")
}
}
}
}对于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()
}
}备选b)创建一个单独的函数来根据枚举计算View:
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)
}
}
}如果返回的视图可以有不同的类型,则需要将其包装在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"))
}
}备选方案c)创建一个单独的View来计算View by enum值:
// Alternative: A separate view
struct StatusView: View {
var status : Status
var body: some View {
switch(status) {
case .loggedIn:
return AnyView(Text("Welcome!"))
case .loggedOut:
return AnyView(Image(systemName: "person.fill"))
case .expired:
return AnyView(Text("Session expired"))
}
}
}发布于 2021-04-10 04:56:34
您可以将枚举与@ViewBuilder一起使用,如下所示...
Declear枚举
enum Destination: CaseIterable, Identifiable {
case restaurants
case profile
var id: String { return title }
var title: String {
switch self {
case .restaurants: return "Restaurants"
case .profile: return "Profile"
}
}
}现在在视图文件中
struct ContentView: View {
@State private var selectedDestination: Destination? = .restaurants
var body: some View {
NavigationView {
view(for: selectedDestination)
}
}
@ViewBuilder
func view(for destination: Destination?) -> some View {
switch destination {
case .some(.restaurants):
CategoriesView()
case .some(.profile):
ProfileView()
default:
EmptyView()
}
}
}如果您想对NavigationLink使用相同的大小写...您可以使用它,如下所示
struct ContentView: View {
@State private var selectedDestination: Destination? = .restaurants
var body: some View {
NavigationView {
List(Destination.allCases,
selection: $selectedDestination) { item in
NavigationLink(destination: view(for: selectedDestination),
tag: item,
selection: $selectedDestination) {
Text(item.title).tag(item)
}
}
}
}
@ViewBuilder
func view(for destination: Destination?) -> some View {
switch destination {
case .some(.restaurants):
CategoriesView()
case .some(.profile):
ProfileView()
default:
EmptyView()
}
}
}https://stackoverflow.com/questions/61839742
复制相似问题