MapKit Tutorial: Getting Started
Learn to use the powerful MapKit framework to build an interactive map, displaying location details and launching Maps for driving directions. By Andrew Tetlaw.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
MapKit Tutorial: Getting Started
35 mins
- Getting Started
- Setting the Visible Area
- Constraining the Camera
- Obtaining Public Art Data
- GeoJSON Properties
- Showing Artwork on the Map
- The Artwork Class
- Adding an Annotation
- Configuring the Annotation View
- The Map View Delegate
- Launching the Maps App
- Handling the Callout
- Setting Your Simulated Location
- Decoding GeoJSON with MKGeoJSONDecoder
- Making Annotations
- Plotting the Artwork
- Customizing Annotations
- Markers with Color-Coding and Text
- Color My World
- Annotations with Images
- Custom Callout Accessory Views
- Where To Go From Here?
Plotting the Artwork
You now have an array of all the public artwork in the dataset, which you’ll add to the map.
Still in ViewController.swift, add the following code at the end of viewDidLoad()
:
loadInitialData()
mapView.addAnnotations(artworks)
addAnnotations
, not the singular addAnnotation
!
Delete the lines that create the single King David Kalakaua map annotation. You don’t need them now that loadInitialData()
creates the artworks
array.
Build and run. Check out all the markers!
Move the map around to see other markers appear. Tap a marker to open its callout bubble, then tap its info button to launch the Maps. Yes, everything you did with the King Kalakaua statue works with all the new artwork as well!
If you’re worried about adding annotations to the map when they’re not visible, don’t be! Apple recommends adding all the annotations right away, whether or not they’re visible in the map region. When you move the map, it automatically displays the visible annotations.
And that’s it! You’ve built an app that parses a GeoJSON file into an array of artworks, then displays them as annotation markers, with a callout info button that launches Maps. Celebrate with a hula dance around your desk! :]
But wait, there are still a few bits of bling to add.
Customizing Annotations
Remember the discipline
property in the Artwork
class? Its values are things like Sculpture and Mural. In fact, the most numerous disciplines are Sculpture, Plaque, Mural and Monument.
It’s easy to color-code the markers, so the most numerous disciplines each have their own colored marker, and all the other disciples have green markers.
Markers with Color-Coding and Text
In Artwork.swift, add this property:
var markerTintColor: UIColor {
switch discipline {
case "Monument":
return .red
case "Mural":
return .cyan
case "Plaque":
return .blue
case "Sculpture":
return .purple
default:
return .green
}
}
Now, you could keep adding code to mapView(_:viewFor:)
, but that would clutter the view controller. There’s a more elegant way, similar to what you can do for table view cells. Create a new Swift file named ArtworkViews.swift and add this code, below the import
statement:
import MapKit
class ArtworkMarkerView: MKMarkerAnnotationView {
override var annotation: MKAnnotation? {
willSet {
// 1
guard let artwork = newValue as? Artwork else {
return
}
canShowCallout = true
calloutOffset = CGPoint(x: -5, y: 5)
rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
// 2
markerTintColor = artwork.markerTintColor
if let letter = artwork.discipline?.first {
glyphText = String(letter)
}
}
}
}
Soon, you’ll register this class as a reusable annotation view for Artwork
annotations. The system passes it an annotation as newValue
, so here’s what you’re doing:
- These lines do the same thing as your
mapView(_:viewFor:)
, configuring the callout. - Then you set the marker’s tint color and also replace its pin icon, or glyph, with the first letter of the annotation’s discipline.
Color My World
Now switch to ViewController.swift, and add this line to viewDidLoad()
, before calling loadInitialData()
:
mapView.register(
ArtworkMarkerView.self,
forAnnotationViewWithReuseIdentifier:
MKMapViewDefaultAnnotationViewReuseIdentifier)
Here, you register your new class with the map view’s default reuse identifier. For an app with more annotation types, you would register classes with custom identifiers.
Scroll down to the extension and delete mapView(_:viewFor:)
.
Build and run. Then move the map around to see the different colored and labeled markers:
In this section of the map, there’s much more art than the map view shows. It reduces clutter by clustering markers that are too close together. In the next section, you’ll see all the annotations.
But first, set the glyph’s image instead of its text. Add the following property to Artwork.swift:
var image: UIImage {
guard let name = discipline else {
return #imageLiteral(resourceName: "Flag")
}
switch name {
case "Monument":
return #imageLiteral(resourceName: "Monument")
case "Sculpture":
return #imageLiteral(resourceName: "Sculpture")
case "Plaque":
return #imageLiteral(resourceName: "Plaque")
case "Mural":
return #imageLiteral(resourceName: "Mural")
default:
return #imageLiteral(resourceName: "Flag")
}
}
These images from icons8.com are already in Assets.xcassets.
Then, in ArtworkViews.swift, replace the glyphText
lines with:
glyphImage = artwork.image
Build and run to see different colored markers with images:
And that’s a segue to another customization option and your next task: Replace the markers with images!
Annotations with Images
In ArtworkViews.swift, add the following class:
class ArtworkView: MKAnnotationView {
override var annotation: MKAnnotation? {
willSet {
guard let artwork = newValue as? Artwork else {
return
}
canShowCallout = true
calloutOffset = CGPoint(x: -5, y: 5)
rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
image = artwork.image
}
}
}
Now, you’re using a plain old MKAnnotationView
instead of an MKMarkerAnnotationView
, and the view has an image
property.
Back in ViewController.swift, in viewDidLoad()
, register this new class, instead of ArtworkMarkerView
:
mapView.register(
ArtworkView.self,
forAnnotationViewWithReuseIdentifier:
MKMapViewDefaultAnnotationViewReuseIdentifier)
Build and run to see all the icons:
Custom Callout Accessory Views
The right callout accessory is an info button, but tapping it opens Maps. So, now you’ll change the button to show the Maps icon.
Find this line in ArtworkView
:
rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
Replace this line with the following code:
let mapsButton = UIButton(frame: CGRect(
origin: CGPoint.zero,
size: CGSize(width: 48, height: 48)))
mapsButton.setBackgroundImage(#imageLiteral(resourceName: "Map"), for: .normal)
rightCalloutAccessoryView = mapsButton
Here, you create a UIButton
, set its background image to a map icon, also from icons8.com in Assets.xcassets, then set the view’s right callout accessory to this button.
Build and run. Then tap a view to see the new Maps button:
The final customization is the detail callout accessory. It’s a single line, which is enough for short location text, but some of the longer location values are truncated like this one:
Now you need a multi-line label. Add the following code to ArtworkView
‘s willSet
:
let detailLabel = UILabel()
detailLabel.numberOfLines = 0
detailLabel.font = detailLabel.font.withSize(12)
detailLabel.text = artwork.subtitle
detailCalloutAccessoryView = detailLabel
Build and run. Then tap a view to see the long location text in full.
Where To Go From Here?
You can download the completed version of the project using the Download Materials button at the top or bottom of this tutorial.
Now you know the basics of using MapKit, but there’s more you can add: map display customizations, geocoding, geofencing, custom map overlays, and more. Apple’s MapKit documentation and Location and Maps Programming Guide are great places to find more information.
Also look at WWDC 2019 Session 236: What’s New in MapKit and MapKit JS, to find more cool features added in iOS 13.
There’s also have a terrific video course, MapKit and Core Location, that covers many awesome topics.
Core Location Tutorial for iOS: Tracking Visited Locations explains how to track your location and display it using MapKit.
If you have any questions as you use MapKit in your apps, or tips for other MapKit users, please join in the forum discussion below!