SwiftUI 4: navigationDestination()'s destination view isn't updated when state changes
The button
is correctly changing the value. By default navigationDestination
does't create a Binding
relation between the parent & child making the passed values immutable
.
So you should create a separate struct
for the child in order to achieve Bindable
behavior:
struct ContentView: View {
@State var data: [Int: String] = [
1: "One",
2: "Two",
3: "Three",
4: "Four"
]
var body: some View {
NavigationStack {
List {
ForEach(Array(data.keys).sorted(), id: \.self) { key in
NavigationLink("\(key)", value: key)
}
}
.navigationDestination(for: Int.self) { key in
SubContentView(key: key, data: $data)
}
}
}
}
struct SubContentView: View {
let key: Int
@Binding var data: [Int: String]
var body: some View {
if let value = data[key] {
VStack {
Text("This is \(value)").padding()
Button("Modify It") {
data[key] = "X"
}
}
}
}
}
How can I pop to the Root view using SwiftUI?
Setting the view modifier isDetailLink
to false
on a NavigationLink
is the key to getting pop-to-root to work. isDetailLink
is true
by default and is adaptive to the containing View. On iPad landscape for example, a Split view is separated and isDetailLink
ensures the destination view will be shown on the right-hand side. Setting isDetailLink
to false
consequently means that the destination view will always be pushed onto the navigation stack; thus can always be popped off.
Along with setting isDetailLink
to false
on NavigationLink
, pass the isActive
binding to each subsequent destination view. At last when you want to pop to the root view, set the value to false
and it will automatically pop everything off:
import SwiftUI
struct ContentView: View {
@State var isActive : Bool = false
var body: some View {
NavigationView {
NavigationLink(
destination: ContentView2(rootIsActive: self.$isActive),
isActive: self.$isActive
) {
Text("Hello, World!")
}
.isDetailLink(false)
.navigationBarTitle("Root")
}
}
}
struct ContentView2: View {
@Binding var rootIsActive : Bool
var body: some View {
NavigationLink(destination: ContentView3(shouldPopToRootView: self.$rootIsActive)) {
Text("Hello, World #2!")
}
.isDetailLink(false)
.navigationBarTitle("Two")
}
}
struct ContentView3: View {
@Binding var shouldPopToRootView : Bool
var body: some View {
VStack {
Text("Hello, World #3!")
Button (action: { self.shouldPopToRootView = false } ){
Text("Pop to root")
}
}.navigationBarTitle("Three")
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
How to navigate from nested Fragment to parent fragment using Jetpack Navigation?
If you have more than one navigation graph, please make sure you're using the right navigation controller. Using Navigation.findNavController(view) in some cases you might need to get your root view to get the root's navigation. Hope, this'll help.
Related Topics
Limiting Concurrent Access to a Service Class with Rxswift
What Does T Equals T Mean in Generics
Inferred to Have Type 'Anyclass', Which May Be Unexpected
How to Encode and Decode the Closures
See Characters in an Nscharacterset (Swift)
New' Is Unavailable: You Cannot Directly Instantiate an Stpissuingcardpin
Swift 3 Warning: Non-Optional Expression of Type 'String' Used in a Check for Optionals
Load Image from Url on Watchkit
Fail to Import Restkit with Cocoapods Dynamic Frameworks
How to Make Xcode Put Starting Brace on New Line in Swift
Why Upload Alamofire Background Request Don't Executes in Background
Remove \\U{E2} Characters from String
How to Re-Order the Realm Table Using Tableview in Swift
How How to Perform Multiple Alamofire Requests That Are Finished One After Another
Swift Callkit Sometimes Can't Activate Loudspeaker After Received Call (Only Incoming Call)
Nstableview Get Indexpath Having the Cell