Reputation: 1632
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.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()
}
}
Upvotes: 16
Views: 2434
Reputation: 1846
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.
Upvotes: 10