There seems to be an \"issue\" with overlays and the MapKit. Unlike annotations, overlays aren\'t reused and therefore when adding multiple overlays would cause
A Swift 4 version of the Objective-C code posted by @wkberg:
MultiPolygon.swift:
import MapKit
/// A concatenation of multiple polygons to allow a single overlay to be drawn in the map,
/// which will consume less resources
class MultiPolygon: NSObject, MKOverlay {
var polygons: [MKPolygon]?
var boundingMapRect: MKMapRect
init(polygons: [MKPolygon]?) {
self.polygons = polygons
self.boundingMapRect = MKMapRect.null
super.init()
guard let pols = polygons else { return }
for (index, polygon) in pols.enumerated() {
if index == 0 { self.boundingMapRect = polygon.boundingMapRect; continue }
boundingMapRect = boundingMapRect.union(polygon.boundingMapRect)
}
}
var coordinate: CLLocationCoordinate2D {
return MKMapPoint(x: boundingMapRect.midX, y: boundingMapRect.maxY).coordinate
}
}
MultiPolygonPathRenderer.swift:
import MapKit
/// A MKOverlayPathRenderer that can draw a concatenation of multiple polygons as a single polygon
/// This will consume less resources
class MultiPolygonPathRenderer: MKOverlayPathRenderer {
/**
Returns a `CGPath` equivalent to this polygon in given renderer.
- parameter polygon: MKPolygon defining coordinates that will be drawn.
- returns: Path equivalent to this polygon in given renderer.
*/
func polyPath(for polygon: MKPolygon?) -> CGPath? {
guard let polygon = polygon else { return nil }
let points = polygon.points()
if polygon.pointCount < 3 { return nil }
let pointCount = polygon.pointCount
let path = CGMutablePath()
if let interiorPolygons = polygon.interiorPolygons {
for interiorPolygon in interiorPolygons {
guard let interiorPath = polyPath(for: interiorPolygon) else { continue }
path.addPath(interiorPath, transform: .identity)
}
}
let startPoint = point(for: points[0])
path.move(to: CGPoint(x: startPoint.x, y: startPoint.y), transform: .identity)
for i in 1..
Usage - Adding the overlay to your MKMapView:
// Add the overlay to mapView
let polygonsArray: [MKPolygon] = self.buildMKPolygons()
let multiPolygons = MultiPolygon.init(polygons: polygonsArray)
self.mapView.addOverlay(multiPolygons)
Usage - Implementing the viewForOverlay in your MKMapViewDelegate:
// Method viewForOverlay:
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
if overlay is MultiPolygon {
let polygonRenderer = MultiPolygonPathRenderer(overlay: overlay)
polygonRenderer.lineWidth = 0.5
polygonRenderer.strokeColor = .mainGreen
polygonRenderer.miterLimit = 2.0
polygonRenderer.fillColor = UIColor.mainGreen.withAlphaComponent(0.2)
return polygonRenderer
}
return MKOverlayRenderer()
}