Detecting touches on MKOverlay in iOS7 (MKOverlayRenderer)
I've done it.
Thanks to incanus and Anna!
Basically I add a TapGestureRecognizer to the MapView, convert the point tapped to map coordinates, go through my overlays and check with CGPathContainsPoint.
Adding TapGestureRecognizer. I did that trick of adding a second double tap gesture, so that the single tap gesture isn't fired when doing a double tap to zoom on map. If anyone knows a better way, I'm glad to hear!
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleMapTap:)];
tap.cancelsTouchesInView = NO;
tap.numberOfTapsRequired = 1;
UITapGestureRecognizer *tap2 = [[UITapGestureRecognizer alloc] init];
tap2.cancelsTouchesInView = NO;
tap2.numberOfTapsRequired = 2;
[self.mapView addGestureRecognizer:tap2];
[self.mapView addGestureRecognizer:tap];
[tap requireGestureRecognizerToFail:tap2]; // Ignore single tap if the user actually double taps
Then, on the tap handler:
-(void)handleMapTap:(UIGestureRecognizer*)tap{
CGPoint tapPoint = [tap locationInView:self.mapView];
CLLocationCoordinate2D tapCoord = [self.mapView convertPoint:tapPoint toCoordinateFromView:self.mapView];
MKMapPoint mapPoint = MKMapPointForCoordinate(tapCoord);
CGPoint mapPointAsCGP = CGPointMake(mapPoint.x, mapPoint.y);
for (id<MKOverlay> overlay in self.mapView.overlays) {
if([overlay isKindOfClass:[MKPolygon class]]){
MKPolygon *polygon = (MKPolygon*) overlay;
CGMutablePathRef mpr = CGPathCreateMutable();
MKMapPoint *polygonPoints = polygon.points;
for (int p=0; p < polygon.pointCount; p++){
MKMapPoint mp = polygonPoints[p];
if (p == 0)
CGPathMoveToPoint(mpr, NULL, mp.x, mp.y);
else
CGPathAddLineToPoint(mpr, NULL, mp.x, mp.y);
}
if(CGPathContainsPoint(mpr , NULL, mapPointAsCGP, FALSE)){
// ... found it!
}
CGPathRelease(mpr);
}
}
}
I could ask for the MKPolygonRenderer which already has the "path" property and use it, but for some reason it is always nil. I did read someone saying that I could call invalidatePath on the renderer and it does fill the path property but it just seems wrong as the point is never found inside any of the polygons. That is why I rebuild the path from the points. This way I don't even need the renderer and just make use of the MKPolygon object.
Detecting a point in a MKPolygon broke with iOS7 (CGPathContainsPoint)
For some reason (possibly a bug), the path
property returns NULL
in the current release of iOS 7.
A workaround is to construct your own CGPathRef
from the points
of the polygon.
With this method, you don't need a reference to the MKPolygonView
or the MKPolygonRenderer
.
For example:
CGMutablePathRef mpr = CGPathCreateMutable();
MKMapPoint *polygonPoints = myPolygon.points;
//myPolygon is the MKPolygon
for (int p=0; p < myPolygon.pointCount; p++)
{
MKMapPoint mp = polygonPoints[p];
if (p == 0)
CGPathMoveToPoint(mpr, NULL, mp.x, mp.y);
else
CGPathAddLineToPoint(mpr, NULL, mp.x, mp.y);
}
CGPoint mapPointAsCGP = CGPointMake(mapPoint.x, mapPoint.y);
//mapPoint above is the MKMapPoint of the coordinate we are testing.
//Putting it in a CGPoint because that's what CGPathContainsPoint wants.
BOOL pointIsInPolygon = CGPathContainsPoint(mpr, NULL, mapPointAsCGP, FALSE);
CGPathRelease(mpr);
This should work on iOS 6 as well.
However, you may want to do this manual construction only if the overlay view's path
property returns NULL
.
Related Topics
How to Set the Full Width of Separator in Uitableview
Autolayout - Intrinsic Size of Uibutton Does Not Include Title Insets
How to Delay a Method Call for 1 Second
How to Add Cgpoint Objects to an Nsarray the Easy Way
When Do I Need to Call Setneedsdisplay in iOS
Swift Modal View Controller with Transparent Background
How to Set Hex Color Code for Background
iOS Convert Large Numbers to Smaller Format
How to Batch Request with Afnetworking 2
Uiscrollview with Centered Uiimageview, Like Photos App
After Upgrading to Xcode 11.2 from Xcode 11.1, App Crashes Due to _Uitextlayoutview
How to Fill Uitableview with a Data from Dictionary. Swift
How to Display Nested Array Data Inside Uitableview Properly with Multiple Level of Sections
Swift - Image Data from Ciimage Qr Code/How to Render Cifilter Output