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
Based on @davidrynn answer i've accomplished a more dynamic and updated result.
Swift 5
Subclass MKMapView:
public class MapView: MKMapView {
public var mapViewProtocol: MapViewProtocol?
public override func touchesEnded(_ touches: Set, with event: UIEvent?) {
if let touch = touches.first {
if touch.tapCount == 1 {
let touchLocation: CGPoint = touch.location(in: self)
let locationCoordinate: CLLocationCoordinate2D = self.convert(touchLocation, toCoordinateFrom: self)
var mkCircleList: [MKCircle] = self.overlays.compactMap { $0 as? MKCircle }
mkCircleList = mkCircleList.filter { $0.contains(locationCoordinate) }
if !mkCircleList.isEmpty {
self.mapViewProtocol?.didTapMKCircles(self, mkCircleList)
}
var mkMultiPolygonList: [MKMultiPolygon] = self.overlays.compactMap { $0 as? MKMultiPolygon }
mkMultiPolygonList = mkMultiPolygonList.filter { $0.contains(locationCoordinate) }
if !mkMultiPolygonList.isEmpty {
self.mapViewProtocol?.didTapMKMultiPolygons(self, mkMultiPolygonList)
}
var mkPolygonList: [MKPolygon] = self.overlays.compactMap { $0 as? MKPolygon }
mkPolygonList = mkPolygonList.filter { $0.contains(locationCoordinate) }
if !mkPolygonList.isEmpty {
self.mapViewProtocol?.didTapMKPolygons(self, mkPolygonList)
}
var mkMultiPolylineList: [MKMultiPolyline] = self.overlays.compactMap { $0 as? MKMultiPolyline }
mkMultiPolylineList = mkMultiPolylineList.filter { $0.contains(locationCoordinate) }
if !mkMultiPolylineList.isEmpty {
self.mapViewProtocol?.didTapMKMultiPolylines(self, mkMultiPolylineList)
}
var mkPolylineList: [MKPolyline] = self.overlays.compactMap { $0 as? MKPolyline }
mkPolylineList = mkPolylineList.filter { $0.contains(locationCoordinate) }
if !mkPolylineList.isEmpty {
self.mapViewProtocol?.didTapMKPolylines(self, mkPolylineList)
}
//TODO
//var mkTileOverlayList: [MKTileOverlay] = self.overlays.compactMap { $0 as? MKTileOverlay }
//mkTileOverlayList = mkTileOverlayList.filter { $0.contains(locationCoordinate) }
self.mapViewProtocol?.didTapMap(self, locationCoordinate)
}
}
super.touchesEnded(touches, with: event)
}
}
After that i created multiple extensions for each mkOverlay type:
MKKCircle
import Foundation
import MapKit
extension MKCircle {
func contains(_ coordinate2D: CLLocationCoordinate2D) -> Bool {
let renderer = MKCircleRenderer(circle: self)
let currentMapPoint: MKMapPoint = MKMapPoint(coordinate)
let viewPoint: CGPoint = renderer.point(for: currentMapPoint)
if renderer.path == nil {
return false
} else {
return renderer.path.contains(viewPoint)
}
}
}
MKMultiPolygon
import Foundation
import MapKit
@available(iOS 13.0, *)
extension MKMultiPolygon {
func contains(_ coordinate2D: CLLocationCoordinate2D) -> Bool {
return self.polygons.filter { $0.contains(coordinate2D) }.isEmpty ? false : true
}
}
MKMultiPolyline
import Foundation
import MapKit
@available(iOS 13.0, *)
extension MKMultiPolyline {
func contains(_ coordinate2D: CLLocationCoordinate2D) -> Bool {
return self.polylines.filter { $0.contains(coordinate2D) }.isEmpty ? false : true
}
}
MKPolygon
import Foundation
import MapKit
extension MKPolygon {
func contains(_ coordinate2D: CLLocationCoordinate2D) -> Bool {
let renderer = MKPolygonRenderer(polygon: self)
let currentMapPoint: MKMapPoint = MKMapPoint(coordinate2D)
let viewPoint: CGPoint = renderer.point(for: currentMapPoint)
if renderer.path == nil {
return false
} else {
return renderer.path.contains(viewPoint)
}
}
}
MKPolyline
import Foundation
import MapKit
extension MKPolyline {
func contains(_ coordinate2D: CLLocationCoordinate2D) -> Bool {
let renderer = MKPolylineRenderer(polyline: self)
let currentMapPoint: MKMapPoint = MKMapPoint(coordinate2D)
let viewPoint: CGPoint = renderer.point(for: currentMapPoint)
if renderer.path == nil {
return false
} else {
return renderer.path.contains(viewPoint)
}
}
}
And finally create and implement the protocol:
public protocol MapViewProtocol {
func didTapMKPolygons(_ mapView: MKMapView, _ mkPolygons: [MKPolygon])
func didTapMKCircles(_ mapView: MKMapView, _ mkCircles: [MKCircle])
func didTapMKPolylines(_ mapView: MKMapView, _ mkPolylines: [MKPolyline])
func didTapMKMultiPolygons(_ mapView: MKMapView, _ mkMultiPolygons: [MKMultiPolygon])
func didTapMKMultiPolylines(_ mapView: MKMapView, _ mkMultiPolylines: [MKMultiPolyline])
func didTapMap(_ mapView: MKMapView, _ clLocationCoordinate2D: CLLocationCoordinate2D)
}