MapKit offers showsTraffic: Bool, which is great for displaying live traffic data on the map. However, MapPolyline sits above it, which makes it quite useless. Is this the expected behaviour?
SwiftUI MapKit
Use the .mapOverlayLevel(level:) modifier on your MapContent to position polylines relative to other map elements. Setting .aboveRoads places polylines above roads but below labels and traffic, keeping traffic data visible. Setting .aboveLabels places them above everything including traffic.
Negative
.aboveRoads still won't place the MapPolyline below the traffic layer.
There's no public API to insert a polyline between road geometry and road labels. That middle layer is what Apple Maps appears to use internally for its own route rendering, but it's private and not accessible to us...
Apple Maps achieves (I guess) that look purely because it has access to an internal rendering pipeline that isn't exposed through MapKit's public APIs
Tested with a simple snippet and confirmed in the same location (next to my house)
Map(position: $cameraPosition) {
UserAnnotation()
if let route {
MapPolyline(route.polyline)
.stroke(.blue, style: StrokeStyle(lineWidth: 8, lineCap: .round))
.mapOverlayLevel(level: .aboveRoads)
}
}
.mapStyle(.standard(
elevation: .automatic,
emphasis: .automatic,
pointsOfInterest: .all,
showsTraffic: true
))
I'm not sure I understand what aspect you're asking for that doesn't match what I already said.
There's no public API to insert a polyline between road geometry and road labels.
There is— that's the aboveRoads level. Here's a screenshot that shows a MapCircle overlay intersecting a major highway junction with traffic, to help make this more obvious than just a polyline. The highway identifier label, as well as the local road level (at the bottom of the map) is clearly above the overly for the aboveRoads version.
private let center = CLLocationCoordinate2D(latitude: 37.33067, longitude: -122.01436)
private let region = MKCoordinateRegion(center: center, latitudinalMeters: 800, longitudinalMeters: 800)
...
VStack(spacing: 0) {
Map(initialPosition: .region(region)) {
MapCircle(center: center, radius: 100)
.foregroundStyle(.black.opacity(0.4))
.stroke(.purple, lineWidth: 10)
.mapOverlayLevel(level: .aboveRoads)
}
.mapStyle(.standard(showsTraffic: true))
.overlay(alignment: .topLeading) {
Text("aboveRoads")
.font(.caption.bold())
.padding(6)
.background(.regularMaterial)
.padding(8)
}
Map(initialPosition: .region(region)) {
MapCircle(center: center, radius: 100)
.foregroundStyle(.black.opacity(0.4))
.stroke(.purple, lineWidth: 10)
.mapOverlayLevel(level: .aboveLabels)
}
.mapStyle(.standard(showsTraffic: true))
.overlay(alignment: .topLeading) {
Text("aboveLabels")
.font(.caption.bold())
.padding(6)
.background(.regularMaterial)
.padding(8)
}
}
What are you trying to achieve that isn't covered by the above?
I still disagree. In which city did you tested this? See this
Here is a code snippet that lets you tap 2 points on the map to calculate a route and verify that MapPolyline is still rendered below the traffic layer in certain cities, despite using .mapOverlayLevel(level: .aboveRoads). Try highways
import SwiftUI
import MapKit
struct ContentView: View {
@State private var position: MapCameraPosition = .region(MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: 51.5, longitude: -0.1),
latitudinalMeters: 2000,
longitudinalMeters: 2000
))
@State private var tappedCoordinates: [CLLocationCoordinate2D] = []
@State private var routePolyline: MKPolyline? = nil
@State private var isCalculating = false
var body: some View {
ZStack(alignment: .bottom) {
MapReader { proxy in
Map(position: $position) {
if let polyline = routePolyline {
MapPolyline(polyline)
.stroke(.blue, lineWidth: 10)
.mapOverlayLevel(level: .aboveRoads)
}
ForEach(tappedCoordinates.indices, id: \.self) { i in
Marker("\(i + 1)", coordinate: tappedCoordinates[i])
.tint(i == 0 ? .green : .red)
}
}
.mapStyle(.standard(showsTraffic: true))
.onTapGesture { screen in
guard let coord = proxy.convert(screen, from: .local) else { return }
if tappedCoordinates.count < 2 {
tappedCoordinates.append(coord)
}
}
}
VStack(spacing: 12) {
if tappedCoordinates.count == 2 {
Button(isCalculating ? "Calculating..." : "Calculate Route") {
Task { await calculateRoute() }
}
.buttonStyle(.borderedProminent)
.disabled(isCalculating)
}
Button("Clear") {
tappedCoordinates = []
routePolyline = nil
}
.buttonStyle(.bordered)
}
.padding()
}
}
private func calculateRoute() async {
guard tappedCoordinates.count == 2 else { return }
isCalculating = true
let request = MKDirections.Request()
request.source = MKMapItem(placemark: MKPlacemark(coordinate: tappedCoordinates[0]))
request.destination = MKMapItem(placemark: MKPlacemark(coordinate: tappedCoordinates[1]))
request.transportType = .automobile
do {
let directions = try await MKDirections(request: request).calculate()
routePolyline = directions.routes.first?.polyline
} catch {
print("Route error: \(error)")
}
isCalculating = false
}
}