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

在SwiftUI视图中使用开关/枚举,swiftui,Swiftui,从Xcode 11.4开始,SwiftUI不允许在函数生成器块(如VStack{})中使用switch语句,失败时出现一般错误,如无法推断一般参数“Content”。如何在SwiftUI中使用switch语句根据枚举值创建不同的视图?SwiftUI视图生成器中的switch受支持,因为Xcode 12: 枚举状态{ 案例日志数据,日志数据,过期 } 结构SwiftUISwitchView:视图{ @状态变量userStatus:Status=.loggedIn var body:一些观点{ VS

从Xcode 11.4开始,SwiftUI不允许在函数生成器块(如VStack{})中使用switch语句,失败时出现一般错误,如无法推断一般参数“Content”。如何在SwiftUI中使用switch语句根据枚举值创建不同的视图?

SwiftUI视图生成器中的switch受支持,因为Xcode 12:

枚举状态{ 案例日志数据,日志数据,过期 } 结构SwiftUISwitchView:视图{ @状态变量userStatus:Status=.loggedIn var body:一些观点{ VStack{ 切换self.userStatus{ 案例:loggedIn: 欢迎! 案例。loggedOut: ImagesystemName:person.fill 案例。过期: 文本会话已过期 } } } } 对于Xcode 11,您可以使用以下变通方法:

将其包装在具有显式返回类型的单个组块中-如果switch语句是function builder块中的唯一语句,则允许此操作:

枚举状态{ 案例日志数据,日志数据,过期 } 结构SwiftUISwitchView:视图{ @状态变量userStatus:Status=.loggedIn var body:一些观点{ VStack{ 组{->中的文本 switchself.userStatus{ 案例:loggedIn: 欢迎回来! 案例。loggedOut: 返回文本请登录 案例。过期: 返回文本会话已过期 } } } } } 结构SwitchUsageInSwiftUI\u预览:PreviewProvider{ 静态var预览:一些视图{ 迅捷视图 } } 备选方案b创建一个单独的函数以基于枚举计算视图:

结构SwiftUISwitchView:视图{ @状态变量userStatus:Status=.loggedIn //如果始终是同一视图,则可以使用某些视图 func viewForstatus:状态->某些视图{ 开关状态{ 案例:loggedIn: 欢迎回来! 案例。loggedOut: 返回文本请登录 案例。过期: 返回文本会话已过期 } } var body:一些观点{ VStack{ viewForstatus:userStatus } } } 如果返回的视图可以有不同的类型,则需要将其包装在AnyView中,因为某些视图要求返回类型在所有情况下都相同:

// 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创建一个单独的视图以按枚举值计算视图:

//备选方案:一个单独的视图 结构状态视图:视图{ 变量状态:状态 var body:一些观点{ 开关状态{ 案例:loggedIn: 返回任意ViewTextWelcome! 案例。loggedOut: 返回AnyViewImagesystemName:person.fill 案例。过期: 返回任何已过期的ViewTextSession } } } 自Xcode 12以来,支持SwiftUI视图生成器中的切换:

枚举状态{ 案例日志数据,日志数据,过期 } 结构SwiftUISwitchView:视图{ @状态变量userStatus:Status=.loggedIn var body:一些观点{ VStack{ 切换self.userStatus{ 案例:loggedIn: 欢迎! 案例。loggedOut: ImagesystemName:person.fill 案例。过期: 文本会话已过期 } } } } 对于Xcode 11,您可以使用以下变通方法:

将其包装在具有显式返回类型的单个组块中-如果switch语句是function builder块中的唯一语句,则允许此操作:

枚举状态{ 案例日志数据,日志数据,过期 } 结构SwiftUISwitchView:视图{ @状态变量userStatus:Status=.loggedIn var body:一些观点{ VStack{ 组{->中的文本 switchself.userStatus{ 案例:loggedIn: 欢迎回来! 案例。loggedOut: 返回文本请登录 案例。过期: 返回文本会话已过期 } } } } } 结构SwitchUsageInSwiftUI\u预览:PreviewProvider{ 静态var预览:一些视图{ 迅捷视图 } } 备选方案b创建一个单独的函数以基于枚举计算视图:

结构SwiftUISwitchView:视图{ @状态变量userStatus:Status=.loggedIn //如果始终是同一视图,则可以使用某些视图 func viewForstatus:状态->某些视图{ 开关状态{ 案例:loggedIn: 欢迎回来! 案例。loggedOut: 返回文本请登录 案例。过期: 返回文本会话已过期 } } var body:一些观点{ VStack{ viewForstatus:userStatus } } } 如果返回的视图可以有不同的类型,则需要将其包装在AnyView中,因为某些视图需要 返回类型在所有情况下都相同:

// 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创建一个单独的视图以按枚举值计算视图:

//备选方案:一个单独的视图 结构状态视图:视图{ 变量状态:状态 var body:一些观点{ 开关状态{ 案例:loggedIn: 返回任意ViewTextWelcome! 案例。loggedOut: 返回AnyViewImagesystemName:person.fill 案例。过期: 返回任何已过期的ViewTextSession } } } 您可以将枚举与@ViewBuilder一起使用,如下所示

去垢枚举

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()
    }
  }
}
您可以将枚举与@ViewBuilder一起使用,如下所示

去垢枚举

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