The Maps app in iOS 10 now includes a heading direction arrow on top of the MKUserLocation
MKAnnotationView
. Is there some way I can add this to MKMapView
in my own apps?
Edit: I'd be happy to do this manually, but I'm not sure if it's possible? Can I add an annotation to the map and have it follow the user's location, including animated moves?
Yes, you can do this manually.
The basic idea is to track user's location with
CLLocationManager
and use it's data for placing and rotating annotation view on the map.Here is the code. I'm omitting certain things that are not directly related to the question (e.g. I'm assuming that user have already authorized your app for location access, etc.), so you'll probably want to modify this code a little bit
ViewController.swift
Here we are doing basic setup of the map view and starting to track user's location and heading with the
CLLocationManager
.UserLocationAnnotation.swift
Very simple
MKPointAnnotation
subclass that is capable of storing heading direction.dynamic
keyword is the key thing here. It allows us to observe changes to theheading
property with KVO.UserLocationAnnotationView.swift
MKAnnotationView
subclass that does the observation of theheading
property and then sets the appropriate rotation transform to it's subview (in my case it's just an image with the arrow. You can create more sophisticated annotation view and rotate only some part of it instead of the whole view.)UIView.animate
is optional. It is added to make rotation smoother.CLLocationManager
is not capable of observing heading value 60 times per second, so when rotating fast, animation might be a little bit choppy.UIView.animate
call solves this tiny issue.Proper handling of
coordinate
value updates is already implemented inMKPointAnnotation
,MKAnnotationView
andMKMapView
classes for us, so we don't have to do it ourselves.I also experienced this same issue (needing an orientation indicator without having the map spin around, similar to the Apple Maps app). Unfortunately Apple has not yet made the 'blue icon for heading' API available.
I created the following solution derived from @alku83's implementation.
Add the delegate method to add a blue arrow icon to the maps location dot
Add the method to create the 'blue arrow icon'.
Add
var headingImageView: UIImageView?
to your class. This is mainly needed to transform/rotate the blue arrow image.(In a different class/object depending on your architecture) Create a location manager instance, with the class conforming to
CLLocationManagerDelegate
protocolEnsure your location manager is tracking user heading data
locationManager.startUpdatingHeading()
and that it stops tracking when appropriatelocationManager.stopUpdatingHeading()
Add
var userHeading: CLLocationDirection?
which will hold the orientation valueAdd the delegate method to be notified of when the heading values change, and change the userHeading value appropriately
Now in your class conforming to MKMapViewDelegate, add the method to 'transform' the orientation of the heading image
I solved this by adding a subview to the
MKUserLocation
annotationView, like so