I’ve filed this as a bug with Apple (FB12119822) since I’m fairly certain there’s nothing wrong with my code, but posting here for posterity and in case other folks have found a workaround.
When navigating between list and detail sections in a NavigationSplitView, the title bar unexpectedly jumps between inline and large display modes. In some instances, the title appears to be empty until the navigation segue is complete, after which it suddenly renders in a large display mode, pushing view content down.
The navigation segue animates the origin title into the “Back” button of the navigation bar, and simultaneously animates the destination’s navigation bar title into a default (large) display mode
The navigation segue animates the origin title into the “Back” button of the navigation bar, but no destination title is displayed. When the segue completes, the ”Back” button text is replaced with the default text (“Back”) and the destination title suddenly appears. (Screen recording)
The above behaviour is exhibited when the NavigationSplitView’s List has a selection argument. When instead the navigationDestination modifier is applied, the title bar of both the origin list and destination detail view is impacted. (Screen recording)
List(selection:)import SwiftUI
fileprivate struct Item: Identifiable, Hashable {
let id = UUID()
}
fileprivate let items = (0...10).map { _ in Item() }
struct ListWithSelectionTitleBarJumpExample: View {
@State var selectedItem: UUID?
var body: some View {
NavigationSplitView {
List(selection: $selectedItem) {
Section {
ForEach(items) { item in
Text(item.id.uuidString)
.tag(item.id)
}
} header: {
Text("Navigable rows")
}
}
.navigationTitle("Navigation Title Jump")
} detail: {
if let selectedItem,
let item = items.first(where: { $0.id == selectedItem }) {
Text(item.id.uuidString)
.navigationTitle("Detail View")
} else {
Text("No selection")
}
}
}
}
struct ListWithSelectionTitleBarJumpExample_Previews: PreviewProvider {
static var previews: some View {
ListWithSelectionTitleBarJumpExample()
}
}
List.navigationDestinationimport SwiftUI
fileprivate struct Item: Identifiable, Hashable {
let id = UUID()
}
fileprivate let items = (0...10).map { _ in Item() }
struct ListWithNavigationDestinationTitleBarJumpExample: View {
var body: some View {
NavigationSplitView {
List {
Section {
ForEach(items) { item in
NavigationLink(value: item) {
Text(item.id.uuidString)
}
}
} header: {
Text("Navigable rows")
}
}
.navigationTitle("Navigation Title Jump")
.navigationDestination(for: Item.self) { value in
Text(value.id.uuidString)
.navigationTitle("Detail View")
}
} detail: {
Text("No selection")
}
}
}
struct ListWithNavigationDestinationTitleBarJumpExample_Previews: PreviewProvider {
static var previews: some View {
ListWithNavigationDestinationTitleBarJumpExample()
}
}
I believe NavigationSplitView gets confused when a detail view has a .navigationBarTitleDisplayMode that is different from the one in the no selection view.
For example, a large title vs no title, an inline title vs a large title, a title with an editor via Binding vs plain text title.
At least your ListWithSelectionTitleBarJumpExample could be "fixed" by adding a placeholder .navigationTitle to the "no selection" view:
// ...
} else {
Text("No selection")
// The workaround:
.navigationTitle(" ")
}
This is, obviously, still a bug, NavigationStack has no problem switching between title modes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With