I have a compilation error when i try to return different custom views that conform to the View protocol from a method. Here is a simple example that describes the issue.
I want to have a method that returns a different custom view based on the enum case. When i try to achieve that, i get different compile errors:
enum AppScreen: String, CaseIterable {
case home
case detail
}
struct ContentView: View {
var body: some View {
NavigationView {
List {
ForEach(AppScreen.allCases, id: \.self) { screen in
NavigationLink(destination: getSomeView(screen)) {
Text(screen.rawValue)
}
}
}
List {
ForEach(AppScreen.allCases, id: \.self) { screen in
NavigationLink(destination: getAnyView(screen)) {
Text(screen.rawValue)
}
}
}
}
}
private func getSomeView(_ screen: AppScreen) -> some View {
switch screen {
case .home:
return HomeView()
case .detail:
return DetailView()
}
}
private func getAnyView(_ screen: AppScreen) -> any View {
switch screen {
case .home:
return HomeView()
case .detail:
return DetailView()
}
}
}
The method getSomeView throws the following compile error: Function declares an opaque return type 'some View', but the return statements in its body do not have matching underlying types
The method getAnyView compiles, but i get the following error when i call it as the destination for the NavigationLink: Type 'any View' cannot conform to 'View'
I'm learning SwiftUI and the new generics features from Swift 5.7. I believe that the behavior that i'm looking for can be achieved. Any help or guidance will be appreciated, thanks in advance!
This is how to achieve what you are trying to do.
getSomeView()
with @ViewBuilder
. This makes it work like var body
which is also a ViewBuilder
allowing you to build different types of views.return
statements.Here is a standalone example based upon your original code:
enum AppScreen: String, CaseIterable {
case home
case detail
}
struct HomeView: View {
var body: some View {
Text("HomeView")
}
}
struct DetailView: View {
var body: some View {
Text("DetailView")
}
}
struct ContentView: View {
var body: some View {
NavigationView {
List {
ForEach(AppScreen.allCases, id: \.self) { screen in
NavigationLink(destination: getSomeView(screen)) {
Text(screen.rawValue)
}
}
}
}
}
@ViewBuilder
private func getSomeView(_ screen: AppScreen) -> some View {
switch screen {
case .home:
HomeView()
case .detail:
DetailView()
}
}
}