Using expanded SwiftUI support for MapKit
Learn how to use SwiftUI to integrate Maps in your apps with extended MapKit features like annotations, overlays, camera controls, and more.
The MapKit implementation for SwiftUI has been somewhat limited to basic features. More advanced implementations, like adding annotations, required the use of UIKit. At WWDC 2023, Apple announced the extension of MapKit features for SwiftUI, enabling the design of more expressive and interactive maps using Views and View Modifiers.
Here are some highlights on what is possible to achieve using MapKit and SwiftUI together on iOS 17.
Check the Developer Documentation for Map protocols and view modifiers that are no longer supported.
Creating a Map
To create a view that presents a map in your application you just need to use the Map
view.
import SwiftUI
import MapKit
struct ContentView: View {
var body: some View {
Map()
}
}
Changing a Map Style
MapKit comes with multiple map styles that can be configured using the .mapStyle
view modifier. Beyond the standard style, maps can be rendered using satellite images with the imagery style. To use satellite images as well as paths of roads and their names, the hybrid style can be used.
import SwiftUI
import MapKit
struct ContentView: View {
let garage = CLLocationCoordinate2D(latitude: 40.83657722488077,
longitude: 14.306896671048852)
var body: some View {
Map {
Marker("Garage", coordinate: garage)
}
.mapStyle(.standard(elevation: .realistic))
}
}
Changing the Map Camera
The camera position can be defined automatically or be initialized with an MKCoordinateRegion
, defined by center coordinates and span to define the zoom level, an MKMapRect
, defined by the corner coordinates of map section, as well as an MKMapItem
that would be placed at the center of the camera view.
import SwiftUI
import MapKit
struct ContentView: View {
let garage = CLLocationCoordinate2D(latitude: 40.83657722488077,
longitude: 14.306896671048852)
let regionCenter = CLLocationCoordinate2D(latitude: 40.83657722488077, longitude: 14.306896671048852)
let regionSpan = MKCoordinateSpan(latitudeDelta: 0.125, longitudeDelta: 0.125)
@State private var position: MapCameraPosition = .region(MKCoordinateRegion(center: regionCenter, span: regionSpan))
var body: some View {
Map(position: $position) {
Marker("Garage", coordinate: garage)
}
.mapStyle(.standard(elevation: .realistic))
}
}
Showing the User Annotation
You can use the UserAnnotation
view to display the user's current location on the map. It can be styled in various ways and is making use of the UserLocation
structure that contains information about the current location of the user.
import SwiftUI
import MapKit
struct ContentViews: View {
let garage = CLLocationCoordinate2D(latitude: 40.83657722488077,
longitude: 14.306896671048852)
@State private var position: MapCameraPosition = .userLocation(fallback: .automatic)
var body: some View {
Map(position: $position) {
Marker("Garage", coordinate: garage)
UserAnnotation()
}
.mapStyle(.standard(elevation: .realistic))
}
}
Adding Controls to a Map
MapKit features a number of controls that allow the user to interact with the map in an easy way.
MapCompass
displays the current orientation of the associated map.MapPitchButton
sets the camera angle to a viewable angle or returns to flat.MapPitchSlider
allows the user to change the pitch of the map.MapScaleView
shows a legend with distance information.MapUserLocationButton
frames the map to the user's current location.MapZoomStepper
allows the user to adjust the zoom level. All of these controls can be added using the.mapControls
modifier now.
import SwiftUI
import MapKit
struct ContentViews: View {
let garage = CLLocationCoordinate2D(latitude: 40.83657722488077,
longitude: 14.306896671048852)
@State private var position: MapCameraPosition = .userLocation(fallback: .automatic)
var body: some View {
Map(position: $position) {
Marker("Garage", coordinate: garage)
}
.mapStyle(.standard(elevation: .realistic))
.mapControls {
MapUserLocationButton()
MapCompass()
MapScaleView()
}
}
}
Adding Markers to a Map
A Marker
is a balloon-shaped annotation marking a map location. To initialise one you need to give it coordinates and a label, or you can use a MKMapItem
as well. They can further be customized with custom images, or monograms to stand out. Here are some examples of how you can create markers:
import SwiftUI
import MapKit
struct ContentView: View {
var body: some View {
Map{
Marker("Garage",
systemImage:"figure.wave",
coordinate: CLLocationCoordinate2D(latitude: 40.836, longitude: 14.306)
Marker("Garage",
image:"ImageAsset",
coordinate: CLLocationCoordinate2D(latitude: 40.856, longitude: 14.316)
Marker("Garage",
monogram:"PAR",
coordinate: CLLocationCoordinate2D(latitude: 40.826, longitude: 14.326)
}
}
}
Adding Annotations to a Map
If you need a more custom annotation you can be created one with the Annotation structure. It needs a label and a coordinate, but then it can be customized with any SwiftUI view.
Here for example, we added a ZStack
of two RoundedRectangle
as well as an Image
to create a custom icon for our garage. You can also hide the annotation titles using the .annotationsTitles(.hidden)
modifier.
import SwiftUI
import MapKit
struct ContentView: View {
let garage = CLLocationCoordinate2D(latitude: 40.83657722488077,
longitude: 14.306896671048852)
var body: some View {
Map {
Annotation(
"Garage",
coordinate: garage
){
ZStack {
RoundedRectangle(cornerRadius: 5)
.fill(.background)
RoundedRectangle(cornerRadius: 5)
.stroke(.secondary, lineWidth: 5)
Image(systemName: "car")
.padding(8)
}
}
.annotationTitles(.hidden)
}
}
}
There is much more!
We are just scratching the surface of what’s possible to do with MapKit and SwiftUI together with the new updates. There are new view and modifiers that allow you to:
- Add overlays to a map
- Search for points of interest
- Select markers
- Calculate travel time and get directions
- Use look around previews
Of course, MapKit still works great with UIKit and there are many more features to bring to SwiftUI. Yet, all the new functionality is super simple to implement and makes MapKit much more accessible within a SwiftUI only approach.
For a deeper dive, have a look at the official developer documentation. The MapKit framework provides powerful ways to give your app a sense of place with maps and location information. Beyond support for SwiftUI, AppKit, and UIKIt, there is also MapKit JS to embed interactive Apple Maps in websites.