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!
CodePudding user response:
This is how to achieve what you are trying to do.
- Mark
getSomeView()
with@ViewBuilder
. This makes it work likevar body
which is also aViewBuilder
allowing you to build different types of views. - Remove the
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()
}
}
}