Reputation: 1333
I have code like this:
List(datalist) { data in
NavigationLink(destination: View1(data: data).headless()) {
Text(data.name)
}
}
where headless() is a way to avoid all the default top views of a NavigationLink and its corresponding init:
extension View {
// https://www.hackingwithswift.com/forums/swiftui/removing-unwanted-and-unknown-whitespace-possibly-a-navigation-bar-above-a-view/7343
func headless() -> some View {
return self.navigationBarTitle("")
.navigationBarHidden(true)
.navigationBarBackButtonHidden(true)
}
}
What I want to do is have a View struct that can be a customized call to NavigationLink that always calls the headless() modifier. I have written this, copying from the declaration of NavigationLink:
struct SimpleNavLink<Destination, Label>: View where Label : View, Destination : View {
private let label: () -> Label
private let destination: () -> Destination
init(@ViewBuilder destination: @escaping () -> Destination, @ViewBuilder label: @escaping () -> Label) {
self.label = label
self.destination = destination
}
var body: some View {
NavigationLink(destination: destination().headless, label: label)
}
}
With that in place I changed the NavigationLink line to this:
SimpleNavLink(destination: View1(data: data)) {
But that gave me the error
Cannot convert value of type 'View1' to expected argument type '() -> Destination'
That was easy enough to solve by just wrapping the destination in { }:
SimpleNavLink(destination: { View1(data: data) } ) {
But WHY? I didn't have to do that for the NavigationLink. When I tried adding @autoclosure to the destination parameter, the compiler said that didn't go with @ViewBuilder
Upvotes: 0
Views: 140
Reputation: 385988
You said
I have written this, copying from the declaration of :
I assume you meant “the declaration of NavigationLink
”. But your original code uses a NavigationLink.init
that is declared like this:
@available(iOS, introduced: 13.0, deprecated: 100000.0, message: "Pass a closure as the destination")
@available(macOS, introduced: 10.15, deprecated: 100000.0, message: "Pass a closure as the destination")
@available(tvOS, introduced: 13.0, deprecated: 100000.0, message: "Pass a closure as the destination")
@available(watchOS, introduced: 6.0, deprecated: 100000.0, message: "Pass a closure as the destination")
public init(destination: Destination, @ViewBuilder label: () -> Label)
This version of init
takes the Destination
by value instead of as a function. It's also going to be deprecated at some point.
So, if you want to mimic the (eventually deprecated) syntax, you need to change your init
to take the Destination
by value instead of as a function. Note also that NavigationLink
does not require @escaping
closures, so perhaps you shouldn't either. Thus:
struct SimpleNavLink<Destination: View, Label: View>: View {
private let label: Label
private let destination: Destination
init(
destination: Destination,
@ViewBuilder label: () -> Label
) {
self.label = label()
self.destination = destination
}
var body: some View {
NavigationLink(
destination: destination.headless(),
label: { label }
)
}
}
Upvotes: 1