I'm working on iOS 17+ app in SwiftUI, which uses MapKit. MapKit's Map view adds a gradient/material view on Toolbar, which is presented on second and every next navigation.
I would like to get the first's navigation behavior, which is no background and no shadow image (navbar divider).
This issue is 100% related to the Map view - commenting it out resolves the issue, but also removes the functionality, which I need.
Code:
struct HomeView: View {
var body: some View {
NavigationStack {
Content(/* properties */)
}
}
}
struct Content: View {
// Properties ...
var body: some View {
Group {
if array.isEmpty {
EmptyStateView()
} else {
ListView(data: array, onDelete: onDelete)
}
}
.accentBackground(strong: true) // << Gradient background
.navigationTitle("Title")
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
AddButton()
}
}
}
}
struct ListView: View {
// Properties ...
var body: some View {
List {
ForEach(data) { list in
Row(/* properties */)
}
.onDelete(perform: onDelete)
}
.scrollContentBackground(.hidden)
}
}
struct Row: View {
// Properties ...
var body: some View {
NavigationLink(destination: DetailsView(list: list)) {
VStack(alignment: .leading) {
Text(list.title)
.font(.headline)
Text(/* sublabel */)
.font(.subheadline)
.foregroundStyle(.secondary)
}
}
}
}
struct DetailsView: View {
// Properties ...
var body: some View {
List {
// Some conditional subviews ...
if let location = list.location {
Section {
// Edit mode conditional remove button ...
PresentableMap(location: location)
.frame(height: 300)
}
}
}
.scrollContentBackground(.hidden)
.accentBackground(strong: true)
.navigationTitle(list.title)
}
}
struct PresentableMap: View {
let location: ListLocation
private var coordinates: CLLocationCoordinate2D {
.init(latitude: location.latitude, longitude: location.longitude)
}
var body: some View {
// MapKit View ⬇️
Map(position: .constant(.camera(.init(centerCoordinate: coordinates, distance: 200))), selection: .constant(location)) {
Marker(coordinate: coordinates) {
Image(systemName: "mappin")
}
}
.clipShape(RoundedRectangle(cornerRadius: 8))
.allowsHitTesting(false)
}
}
What I tried:
.toolbarBackground(.hidden, for: .navigationBar)
and other SwiftUI modifiers for hidden navbar background - resolves the issue, but also removes the toolbar background for inline navbar, which is presented during scroll. I would like to keep the large title style and present inline navbar only during scroll.
Screenshot of the bugged scroll:
inputViewController
or inputAccessoryViewController
are nil
.On the gif above you can see that overriding the background respects the safe area, however, the toolbar material added by Map view ignores the safe area.
What do I expect:
It seems to help to add a modifier for .toolbarBackgroundVisibility
that sets the visibility to .automatic
, even though you would expect this to be the default:
// DetailsView
List {
// Some conditional subviews ...
if let location = list.location {
Section {
// Edit mode conditional remove button ...
PresentableMap(location: location)
.frame(height: 300)
}
}
}
.scrollContentBackground(.hidden)
.accentBackground(strong: true)
.navigationTitle(list.title)
.toolbarBackgroundVisibility(.automatic, for: .navigationBar) // 👈 here
The modifier .toolbarBackgroundVisibility
was introduced in iOS 18. For iOS 16 and 17, use .toolbarBackground
instead:
.toolbarBackground(.automatic, for: .navigationBar)