Reputation: 73
I've begun learning SwiftUI, but have had some issues when building up my NavigationView - I'm not sure if this is a bug, or if I'm misunderstanding how nested navigation links should work!
This is my current code:
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
ViewOne()
}
}
}
struct ViewOne: View {
@State var isActiveOne: Bool = true
var body: some View {
VStack {
Text("View One")
NavigationLink(
destination: ViewTwo(),
isActive: $isActiveOne,
label: { EmptyView() }
)
Button(
action: { self.isActiveOne = true },
label: { Text("Set isActiveOne=true") }
)
}
}
}
struct ViewTwo: View {
@State var isActiveTwo: Bool = true
var body: some View {
VStack {
Text("View Two")
NavigationLink(
destination: Text("Success!"),
isActive: $isActiveTwo,
label: { EmptyView() }
)
Button(
action: { self.isActiveTwo = true },
label: { Text("Set isActiveTwo=true") }
)
}
}
}
struct ContentView_Preview: PreviewProvider {
static var previews: some View {
ContentView()
}
}
I expect that:
However, when I run this code on the iOS 14.5 simulator, the second NavigationLink is not automatically displayed (and I just see the ViewTwo Button text).
What I also find strange is that if I default isActiveTrue to false, and then press the button, it navigates correctly - something about the combination of the default "true" state + the nested navigation link seems to be causing the issue.
Any idea if this is a bug in SwiftUI? Or have I done something wrong with my setup here?
Any thoughts would be a huge help - I've been banging my head against the wall for a while now...
Upvotes: 7
Views: 700
Reputation: 4795
This looks like a bug, you can file it at https://feedbackassistant.apple.com
A temporary workaround would be to put your NavigationLink
s inside a List. That seems to work on iOS 14.5 and 15 (beta 2)
If you don't want the List behaviour/look then you can put the list on the background and make it transparent (with the opacity
modifier)
Here is an example of the invisible List workaround:
struct WorkaroundLink<Destination: View>: View {
let destination: Destination
let isActive: Binding<Bool>
var body: some View {
List {
NavigationLink(
destination: destination,
isActive: isActive,
label: { EmptyView() }
)
}.opacity(0.01)
}
}
extension View {
func workaroundLink<D: View>(to destination: D, isActive: Binding<Bool>) -> some View {
background(WorkaroundLink(destination: destination, isActive: isActive))
}
}
Rewriting your example with this construct becomes:
struct ContentView: View {
var body: some View {
NavigationView { ViewOne() }
}
}
struct ViewOne: View {
@State var isActiveOne = true
var body: some View {
VStack {
Text("View One")
Button("Set isActiveOne=true") { isActiveOne = true }
}.workaroundLink(to: ViewTwo(), isActive: $isActiveOne)
}
}
struct ViewTwo: View {
@State var isActiveTwo = true
var body: some View {
VStack {
Text("View Two")
Button(
action: { self.isActiveTwo = true },
label: { Text("Set isActiveTwo=true") }
)
}.workaroundLink(to: Text("Success!"), isActive: $isActiveTwo)
}
}
Upvotes: 5