Calls to NavigationPath.removeLast(_:)
will successfully remove items from the path, but the navigation stack UI fails to correctly update if a view in an intermediate path item had a focused searchable
modifier.
In this first video, the searchable modifier is unused. I can navigate to the list, make a selection and return home:
In this second example, the searchable modifier is focused and a selection from the list is made. In the final screen, if I attempt to return home we can see that the navigation path size decreases but the view does not change. If the button is pressed again, we attempt to remove path items that no longer exist, causing a fatal error.
Minimal Reproducible Code:
import SwiftUI
@main
struct NavigationStackRemoveLastNBugApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContentView: View {
@State private var navigationPath = NavigationPath()
var body: some View {
NavigationStack(path: $navigationPath) {
List {
Button("List") {
navigationPath.append(NavigationDestination.listView)
}
}
.navigationDestination(for: NavigationDestination.self) { destination in
switch destination {
case let .selectionView(int):
SelectionView(selectedNumber: int)
case .listView:
ListView()
}
}
.navigationTitle("Home")
}
.environment(\.navigationPath, $navigationPath)
}
}
enum NavigationDestination: Hashable {
case listView
case selectionView(Int)
}
struct ListView: View {
@Environment(\.navigationPath) var navigationPath
@State private var query = ""
var body: some View {
List(1..<5, id: \.self) { int in
Button {
navigationPath?.wrappedValue.append(NavigationDestination.selectionView(int))
} label: {
Text(int, format: .number)
}
}
.searchable(text: $query, placement: .navigationBarDrawer(displayMode: .always))
}
}
struct SelectionView: View {
@Environment(\.navigationPath) var navigationPath
let selectedNumber: Int
@State private var pathSize: Int?
var body: some View {
List {
LabeledContent("Selection", value: selectedNumber.formatted())
if let pathSize {
LabeledContent("Navigation Path Size", value: pathSize.formatted())
}
Button("Back Home") {
navigationPath?.wrappedValue.removeLast(2)
pathSize = navigationPath?.wrappedValue.count
}
}
.task {
pathSize = navigationPath?.wrappedValue.count
}
}
}
extension EnvironmentValues {
@Entry var navigationPath: Binding<NavigationPath>?
}
#Preview {
ContentView()
}
FB20395585