July 10, 2010

iOS 4 and Map Kit Overlays with MonoTouch

One of the "over 100 new features" in iOS 4 that I've been especially interested in are Map Kit overlays. Previously, developers were limited to using annotations to express points on a map. If you wanted to draw a shape of some sort you were more or less up a creek.

Overlays are a special kind of annotation designed to represent an area on a map. iOS 4's Map Kit comes with some common shapes built in (rectangles, circles, polygons, etc). As I understand it it's also possible to make your own custom shapes.

Each overlay object holds data to represent the shape and has a corresponding view that tells the MKMapView's delegate how to draw the overlay. As an example here's how one might draw a circle overlay with a 100 meter radius around the Empire State Building. The code below shows how to do this in C# via MonoTouch.

CLLocationCoordinate2D empireStBld = new CLLocationCoordinate2D(40.748433, -73.985656);
double radiusInMeters = 100d;
MKCircle circle = MKCircle.Circle(empireStBld, radiusInMeters);
MapView.Delegate = new MapViewDelegate(circle);

The only thing left is that the MapViewDelegate class needs to be set up to give an appropriate view for the overlay:

public class MapViewDelegate : MKMapViewDelegate
private MKCircle _circle = null;
private MKCircleView _circleView = null;

public MapViewDelegate(MKCircle circle)
_circle = circle;

public override MKOverlayView GetViewForOverlay(MKMapView mapView, NSObject overlay)
if ((_circle != null) && (_circleView == null))
_circleView = new MKCircleView(_circle);
_circleView.FillColor = UIColor.Cyan;
return _circleView;


Slodge said...

Thanks for the post - very interesting. I've recently coded this type of functionality myself using overlaid custom views and annotations.

One thing I've recently discovered is that MonoTouch doesn't seem to like the Delegate member any more - it seems more reliable to use the callback instead - e.g. mapKitView.GetViewForAnnotation = delegate...

Mark said...

Good thoughts. For myself the MKMapView delegate property ended up doing the job but I could see how using a C# delegate would be a much cleaner implementation.

Mike said...

Nice post! FYI, you don't need to pass the MKCircle to to your delegate via it's constructor. The second argument to the GetViewForOverlay method contains the MKOverlay; just cast it to your MKOverlay subclass (MKCircle in your case).


Mark said...

Thanks for the tip, Mike!