Custom compass position in MKMapView

For map views in native iOS apps MKMapView is my first choice. While implementing an map based app I came to the point where the compass was showing under a menu component. This is because the default compass position is in the top right corner of the map view. So there were two solutions to the problem:

  1. Change the position of the compass
  2. Remove the compass and implement a custom one

Although the second option sounded tempting, the first one seemed to be the obvious choice. But then I learned that the MKMapView doesn't let you do anything with its compass besides the possibility to show or hide it via the 'showCompass' function. I was surprised by this fact, because on the iOS default map app you can see the compass on a custom position.

Custom compass position in apple maps app
Custom compass position in apple maps app

Solving the puzzle

By analyzing the issue I saw the compass is a subview of the map with a custom class called 'MKCompassView'. As the class itself is private API it is not exposed for external use, but I don't need that. To set a new position for the compass I subclassed the MKMapView component and overrode the layoutSubviews function to change the frame of the MKCompassView.

As you can see this is really easy. Then I just had tell the app to use the map view subclass as the map component and my problem was solved.

 
App showing the compass at a custom position on a MKMapView
App showing the compass at a custom position on a MKMapView
 

Make it useful

Then I realized that a static position isn't good at all in my case, you will see the reason later. So I made the position variable and added a simple animation. The final code looks like this:

Inside the app it looks like this:

 
Animated custom compass position on a MKMapView
Animated custom compass position on a MKMapView