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:
- Overriding UINavigationBarAppearance – breaks whole app.
- Overriding UINavigationBar by its properties using SwiftUIIntrospect – can be used only on the NavigationStack, which leds to the breaking Home and Details views, similar behavior to the first point. Can’t Introspect navigation controller on Map view – I can only Introspect Map, which is MKMapView, which is UIView, which doesn’t have access to NavigationController and its NavigationBar.
inputViewController
orinputAccessoryViewController
arenil
. - Changing the toolbar color to red (which I don’t like, but shows how the app behaves; I don’t want to use any color, even matching one, because it results in the ugly design, where the space is anyway divided and doesn’t match the linear gradient background):
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:
- If that’s possible, I would like to keep the List (+its current style) and native NavigationBar with large title.
- Such behavior: