As far as I know, there is no built in methods to do this. Furthermore, official documentation is stating:
You use this class as-is to display map information and to manipulate the map contents from your application. You can center the map on a given coordinate, specify the size of the area you want to display, and annotate the map with custom information.
So, to do what you are trying to achieve, you need to use two MKMapView
, one over the other.
Project link
I made a simple project to show you the functionality, you can find it here: https://github.com/leonardfactory/mapview-polygon-mask
Screenshot
Here you can see the inner mapView displaying a zoomed map in a random polygon.
Explanation
Start adding two MKMapView, either programmatically or with storyboards.
After this, you can mask the topmost MKMapView
with a CAShapeLayer
, which path has been set using points from the MKPolygon
.
MKPolygon
however only stores MKMapPoint
, so we need to transform these in CGPoint. What can we do?
An useful method to do this is provided by MKMapView
itself, convertCoordinate:toPointInView:
, that translates CLLocationCoordinate2D points into normal CGPoint, for example we can write a method like this:
/**
* Convert between MKMapPoint and CGPoint, to be used as masking path point.
*
* @param point The MKMapPoint to be converted
*
* @return The CGPoint, converted in UIView coords from MKMapPoint provided
*/
- (CGPoint) convertPointToMapView:(MKMapPoint) point
{
return [self.mainMapView convertCoordinate:MKCoordinateForMapPoint(point) toPointToView:self.mainMapView];
}
Given a polygon so, you need only to create a CAShapeLayer path, using this helper method, and apply it as a mask to the other MKMapView
, like this:
// Create a CAShapeLayer to hold masking path
CAShapeLayer *maskLayer = [CAShapeLayer layer];
CGMutablePathRef mask = CGPathCreateMutable();
// First point...
CGPoint firstPoint = [self convertPointToMapView:polygon.points[0]];
CGPathMoveToPoint(mask, NULL, firstPoint.x, firstPoint.y);
// Then with some simple CG functions we can draw all the mask
for(NSUInteger i = 0; i < polygon.pointCount - 1; i++)
{
CGPoint nextPoint = [self convertPointToMapView:polygon.points[i+1]];
CGPathAddLineToPoint(mask, NULL, nextPoint.x, nextPoint.y);
}
// Close path
CGPathCloseSubpath(mask);
maskLayer.path = mask;
CGPathRelease(mask);
// Mask the second MKMapView
self.backgroundMapView.layer.mask = maskLayer;
Some things to note:
polygon
is a MKPolygon. If you need to draw one from taps, you can use the MKMapView method convertPoint:toCoordinateInView:, which does the exact opposite of the methodconverCoordinate:toPointInView
I used before.polygon.points
is a C array ofMKMapPoint
(so its type isMKMapPoint *
)