Skip to content

Instantly share code, notes, and snippets.

@chriseidhof
Created December 2, 2021 15:27
Show Gist options
  • Save chriseidhof/f7a19206d07ab04335f4156d9e99f40e to your computer and use it in GitHub Desktop.
Save chriseidhof/f7a19206d07ab04335f4156d9e99f40e to your computer and use it in GitHub Desktop.
import SwiftUI
struct DetailView: View {
@Binding var showDetail: Bool
var body: some View {
List {
NavigationLink("detail", isActive: $showDetail) {
Text("Detail")
}
}
}
}
struct MyList: View {
@Binding var levels: [Bool]
var body: some View {
List {
NavigationLink("Detail", isActive: $levels[0]) {
DetailView(showDetail: $levels[1])
}
}
.overlay(
Button("Navigate To Detail") {
levels = [true, true]
}
)
}
}
struct ContentView: View {
@State var levels = [false, false]
var body: some View {
NavigationView {
MyList(levels: $levels)
}
.navigationViewStyle(.stack)
.overlay(Text(levels.map { $0 ? "t" : "f"}.joined()), alignment: .bottom)
}
}
@bigmountainstudio
Copy link

bigmountainstudio commented Dec 4, 2021

A couple of notes from testing:

While this causes navigation to pop:
DetailView(showDetail: $levels[1])

These options do not:
MyListDetailView(showDetail: .constant(true))
MyListDetailView(showDetail: .constant(levels[1]))

I also tried:

  • Creating and passing an ObservableObject
  • Using @EnvironmentObject to share levels data

Neither worked. 🙁

I submitted a Feedback for this (FB9795803).

@chriseidhof
Copy link
Author

Thanks. Yes, I have tried those things as well. It's easy to "fix" this by disabling various parts, but in the end, I "only" want navigation that's driven by a single @State property.

@dzmitry-antonenka
Copy link

Hello @chriseidhof , I think there's related post on Apple Forum. When parent view state changes, Navigation automatically pops out child views (on iOS14.0 it propagated changes to update child views instead AFAIK). Unfortunately I don't have 14.0SDK to verify for this use-case

@urbanp11
Copy link

I don't think SwiftUI is ready for this kind of navigation yet. Navigation is controlled by stated, but it has only 2 states... may be we need more? Somehow there is a missing state for performing the action, etc. I would like some interface like withAnimation...

performNavigation(withAnimaion: .animateLastOnly) {
   levels = [true, true]
}

Also it would be awesome if it would work for closing too.

I think for now, you can use workaround:

Button("Navigate To Detail") {
    levels = [true, false]

    // slow down due to the opening of the first screen
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
        levels = [true, true]
    }
}

Code with changes:

import SwiftUI

struct DetailView: View {
    @Binding var showDetail: Bool

    var body: some View {
        List {
            NavigationLink("detail", isActive: $showDetail) {
                Text("Detail")
            }
        }
    }
}

struct MyList: View {
    @Binding var levels: [Bool]

    var body: some View {
        List {
            NavigationLink("Detail", isActive: $levels[0]) {
                DetailView(showDetail: $levels[1])
            }
        }
        .overlay(
            Button("Navigate To Detail") {
                levels = [true, false]

                // slow down due to the opening of the first screen
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                    levels = [true, true]
                }
            }
        )
    }
}

struct ContentView: View {
    @State var levels = [false, false]

    var body: some View {
        NavigationView {
            MyList(levels: $levels)
        }
        .navigationViewStyle(.stack)
        .overlay(Text(levels.map { $0 ? "t" : "f"}.joined()), alignment: .bottom)
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment