Issue
This Content is from Stack Overflow. Question asked by Nahuel Roldan
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!
Solution
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()
}
}
}
This Question was asked in StackOverflow by Nahuel Roldan and Answered by vacawama It is licensed under the terms of CC BY-SA 2.5. - CC BY-SA 3.0. - CC BY-SA 4.0.