SwiftUI is a very vast collection of features designed by Apple to make iOS development…swift-er. One of those handy features is it’s ability to make maps, specifically with MapKit.
Requirements: To use these MapKit features, you need to use Xcode 15 and later.
MapKit is one of Apple’s API frameworks that allows iOS developers to build map-centered views and apps easily and efficiently.
Based on the Apple documentation, MapKit can:
- Embed maps directly into your app’s windows and views.
- Add annotations and overlays to a map to call out points of interest.
- Add LookAround capabilities to enable users to explore locations at street level.
- Respond to user interactions with well known points of interest, geographical features, and boundaries.
- Provide text completion for search bars to make it easy for users to search for a destination or point of interest.
Let’s start with a basic map.
To create a basic map, you first need to import MapKit into your Swift file. Then simply call Map() in the view.
import SwiftUI
import MapKit
struct MapContentView: View {
var body: some View {
Map()
}
}
#Preview {
MapContentView()
}
Congratulations, you made a map! As you can tell this is just the bare bones. Now that you have a map, you have to customize it to fit your needs.
Map Style
MapKit provides a couple of different map styles, such as standard
, imagery
, and hybrid
.
Standard
The standard style is the default and can be seen in the map we just made. It marks most roads and road names, as well as location markings. Essentially a mini Apple Maps without functionality.
Imagery
The imagery style provides a rendered satellite view map. Unlike standard, on imagery, roads and locations are not marked.
import SwiftUI
import MapKit
struct MapContentView: View {
var body: some View {
Map().mapStyle(.imagery)
}
}
#Preview {
MapContentView()
}
Hybrid
Want rendered satellite view and road/location names? Then the hybrid style is for you! Hybrid combines the view of imagery
and the road/location naming of standard
, hence the name hybrid.
import SwiftUI
import MapKit
struct MapContentView: View {
var body: some View {
Map().mapStyle(.hybrid)
}
}
#Preview {
MapContentView()
}
Additional Map Style Features
You can also add some additional features to the styles:
elevation
(hybrid/standard): whether the maps render elevationshowsTraffic
(hybrid/standard) : whether the map can display trafficpointsOfInterest
(hybrid/standard) : a collection of certainPointOfInterestCategories
objects for the map to showemphasis
(standard) : dictates how the app emphasizes certain features
For more information, visit Apple documentation for Map Styles.
Now that we have a general map, let’s add Markers. In MapKit, markers are a balloon-shaped annotation that marks a location based on a set of coordinates.
To create a marker, start with a CLLocationCoordinate2D
object to represent your coordinate. Then, add it to your Map's contents through the Marker()
class. The example below hardcodes a coordinate for Robarts Library but it still
takes the same approach if you want to set a coordinate dynamically.
import SwiftUI
import MapKit
struct MapContentView: View {
let robarts = CLLocationCoordinate2D(latitude: 43.664486, longitude: -79.399689)
var body: some View {
Map(){
Marker("Robarts", coordinate: robarts)
}
}
}
#Preview {
MapContentView()
}
There are a couple of ways to customize your marker, such as color and what is displayed in the marker bubble.
Color
To change the color of your marker you can apply the .tint()
method. Tint takes in a Color object so you can either do a system color such as .blue
or your own custom color.
Marker("Robarts", coordinate: robarts).tint(.blue)
Icon
To change what is displayed in the Marker bubble you can add the systemImage
, image
, or monogram
parameters to your Marker as shown below.
System Image:
Marker("Bahen", systemImage: "star.fill", coordinate: bahen)
Image:
Marker("Robarts", image: "<Your Image Name>", coordinate: robarts)
Monogram
Marker("University College", monogram: Text("UC"), coordinate: uc)
If you want more freedom with your designing map pins, try using Annotations instead.
Annotations allow for MapKit developers to completely redesign the location coordinate indicators.
Unlike markers which had a set amount of parameters and there was no way to escape the bubble, Annotations instead takes in a Swift UI View()
.
For example, here we made the annotation to just be a system image with padding rather than a marker bubble.
import SwiftUI
import MapKit
struct MapContentView: View {
let robarts = CLLocationCoordinate2D(latitude: 43.664486, longitude: -79.399689)
var body: some View {
Map(){
Annotation("Robarts", coordinate: robarts){
Image(systemName: "books.vertical")
.padding(6)
.foregroundColor(.white)
.background(.blue)
}
}
}
}
#Preview {
MapContentView()
}
Overall, the annotations allow you to make the map pins completely your own. The possibilities are endless.
By default the map focuses on the map contents (markers, annotations, etc). To focus on a particular region or location, we can use MapCameraPosition
. This can be helpful in a couple cases such as:
- When you finish searching for a specific location, focus the map on that location
- Focus the map on the location of the user
- If the user presses a certain button, change map focus
The default of the MapCameraPosition
is known as .automatic
. It will focus on the content of the map. The map without a camera position already does this, but .automatic
could be helpful to update the camera position back to its original state when zooming in/out too much or when you jump between different camera positions.
@State private var cameraPosition: MapCameraPosition = .automatic
An example of using MapCameraPosition
to focus on a location is setting .region
. In the example below, we focus the map on the CN Tower even though the marker is at Robarts.
import SwiftUI
import MapKit
struct MapContentView: View {
let robarts = CLLocationCoordinate2D(latitude: 43.664486, longitude: -79.399689)
@State private var cameraPosition: MapCameraPosition = .region(MKCoordinateRegion(
center: .init(latitude: 43.6426, longitude: -79.3871),
span: .init(latitudeDelta: 0.01, longitudeDelta: 0.01))
)
var body: some View {
Map(position: $cameraPosition){
Marker("Robarts", coordinate: robarts)
}
}
}
#Preview {
MapContentView()
}
Beyond these introductory examples, MapCameraPosition
has a big potential and is very useful when creating dynamic maps.
MapKit for SwiftUI is very large and has a lot of possible implementations, so this tutorial was just the tip of the iceberg! Below are some additional resources that could help with your MapKit journey.
How to...
For general information, refer to the Apple MapKit Documentation. It is very helpful, but a bit difficult to navigate.