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.
Steps to reproduce
- Create a NavigationSplitView with a sidebar of navigable List items and a detail view corresponding to the selected item with a navigation bar title
- Navigate into the detail view
Expected result
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
Actual result
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)
Additional observations
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)
Code samples
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.navigationDestination
import 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()
}
}