I have an MKMapView with possibly hundreds of polygons drawn. Using MKPolygon and MKPolygonRenderer as one is suppose to on iOS7.
What I need is a way of acting upon
UPDATED (For Swift 3 & 4) I'm not sure why people are adding a UIGestureRecognizer to the mapView when mapView already has a number of gesture recognizers running. I found that these methods inhibit the normal functionality of the mapView, in particular, tapping on an annotation. Instead, I'd recommend subclassing the mapView and overriding the touchesEnded method. We can then use the methods others have suggested in this thread and use a delegate method to tell the ViewController to do whatever it needs to do. The "touches" parameter has a set of UITouch objects that we can use:
import UIKit
import MapKit
protocol MapViewTouchDelegate: class {
func polygonsTapped(polygons: [MKPolygon])
}
class MyMapViewSubclass: MapView {
weak var mapViewTouchDelegate: MapViewTouchDelegate?
override func touchesEnded(_ touches: Set, with event: UIEvent?) {
if let touch = touches.first {
if touch.tapCount == 1 {
let touchLocation = touch.location(in: self)
let locationCoordinate = self.convert(touchLocation, toCoordinateFrom: self)
var polygons: [MKPolygon] = []
for polygon in self.overlays as! [MKPolygon] {
let renderer = MKPolygonRenderer(polygon: polygon)
let mapPoint = MKMapPointForCoordinate(locationCoordinate)
let viewPoint = renderer.point(for: mapPoint)
if renderer.path.contains(viewPoint) {
polygons.append(polygon)
}
if polygons.count > 0 {
//Do stuff here like use a delegate:
self.mapViewTouchDelegate?.polygonsTapped(polygons: polygons)
}
}
}
}
super.touchesEnded(touches, with: event)
}
Don't forget to set the ViewController as the mapViewTouchDelegate. I also found it handy to make an extension for MKPolygon:
import MapKit
extension MKPolygon {
func contain(coor: CLLocationCoordinate2D) -> Bool {
let polygonRenderer = MKPolygonRenderer(polygon: self)
let currentMapPoint: MKMapPoint = MKMapPoint(coor)
let polygonViewPoint: CGPoint = polygonRenderer.point(for: currentMapPoint)
if polygonRenderer.path == nil {
return false
}else{
return polygonRenderer.path.contains(polygonViewPoint)
}
}
}
Then the function can be a little cleaner and the extension may be helpful somewhere else. Plus it's swifty-ier!
override func touchesEnded(_ touches: Set, with event: UIEvent?) {
if let touch = touches.first {
if touch.tapCount == 1 {
let touchLocation = touch.location(in: self)
let locationCoordinate = self.convert(touchLocation, toCoordinateFrom: self)
var polygons: [MKPolygon] = []
for polygon in self.overlays as! [MKPolygon] {
if polygon.contains(coordinate: locationCoordinate) {
polygons.append(polygon)
}
}
if polygons.count > 0 {
//Do stuff here like use a delegate:
self.mapViewTouchDelegate?.polygonsTapped(polygons: polygons)
}
}
}
super.touchesEnded(touches, with: event)
}