I am trying to display any overlay on the map. I have followed many many tutorials but nothing works. The map will always load with no errors but the overlay will never show on the map.
I am trying to get this , an inverted circle, to show on the map.
import Foundation
import UIKit
import MapKit
class MKInvertedCircleOverlayRenderer: MKOverlayRenderer {
var fillColor: UIColor = UIColor.red
var strokeColor: UIColor = UIColor.blue
var lineWidth: CGFloat = 3
var circle: MKCircle
init(circle: MKCircle) {
self.circle = circle
super.init(overlay: circle)
}
override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) {
let path = UIBezierPath(rect: rect(for: MKMapRect.world))
let excludePath: UIBezierPath = UIBezierPath(roundedRect: CGRect(x: circle.coordinate.latitude, y: circle.coordinate.longitude,
width: circle.boundingMapRect.size.width,
height: circle.boundingMapRect.size.height),
cornerRadius: CGFloat(circle.boundingMapRect.size.width))
context.setFillColor(fillColor.cgColor)
path.append(excludePath)
context.addPath(path.cgPath)
context.fillPath(using: .evenOdd)
context.addPath(excludePath.cgPath)
context.setLineWidth(9 / zoomScale)
context.setStrokeColor(strokeColor.cgColor)
context.strokePath()
//line showing circle radius
let lineBeginPoint = CGPoint(x: excludePath.bounds.midX, y: excludePath.bounds.midY)
let lineEndPoint = CGPoint(x: excludePath.bounds.maxX, y: excludePath.bounds.midY)
let linePath: UIBezierPath = UIBezierPath()
linePath.move(to: lineBeginPoint)
linePath.addLine(to: lineEndPoint)
context.addPath(linePath.cgPath)
context.setLineWidth(6/zoomScale)
context.setStrokeColor(UIColor.black.cgColor)
context.setLineDash(phase: 1, lengths: [20 / zoomScale, 10 / zoomScale])
context.strokePath()
// circle at the end of the line above
let circleSize: CGFloat = 30/zoomScale
let circleRect = CGRect(origin: CGPoint(x: lineEndPoint.x - (circleSize/2), y: lineEndPoint.y - (circleSize/2)),
size: CGSize(width: circleSize, height: circleSize))
let circlePath: UIBezierPath =
UIBezierPath(roundedRect: circleRect, cornerRadius: circleSize)
context.addPath(circlePath.cgPath)
context.setFillColor(UIColor.black.cgColor)
context.fillPath()
}
}
import Foundation
import MapKit
import UIKit
class MKInvertedCircle : NSObject, MKOverlay {
var coordinate: CLLocationCoordinate2D
var boundingMapRect: MKMapRect {
return MKMapRect.world
}
init(center coord: CLLocationCoordinate2D) {
self.coordinate = coord
}
}
viewcontroller
import MapKit
import UIKit
import Foundation
class ViewController: UIViewController, MKMapViewDelegate {
private let locationManager = CLLocationManager()
private var currentCoordinate: CLLocationCoordinate2D?
@IBOutlet weak var mapView: MKMapView!
func addCircleOverlay() {
let overlay = MKInvertedCircle(center: CLLocationCoordinate2D())
mapView.addOverlay(overlay)
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
if overlay is MKInvertedCircle {
let circleRenderer = MKInvertedCircleOverlayRenderer(circle: MKCircle())
return circleRenderer
}
else {
return MKOverlayRenderer(overlay: overlay)
}
}
// if screen loads ask for location permissions
override func viewDidLoad() {
super.viewDidLoad()
configureLocationServices()
mapView.delegate = self;
// Do any additional setup after loading the view.
}
//how to ask for location permissions
private func configureLocationServices() {
locationManager.delegate = self
//check location permissions
let status = CLLocationManager.authorizationStatus()
//if location permissions not set, ask
if status == .notDetermined {
locationManager.requestAlwaysAuthorization()
} else if status == .authorizedAlways || status == .authorizedWhenInUse {
//begin tracking location
beginLocationUpdates(locationManager: locationManager)
}
}
//begin tracking location
private func beginLocationUpdates(locationManager: CLLocationManager) {
//show blue dot
mapView.showsUserLocation = true
//track location to best of phones ability
locationManager.desiredAccuracy = kCLLocationAccuracyBest
//start updating location
locationManager.startUpdatingLocation()
}
//zoom to location
private func zoomToLatestLocation(with coordinate: CLLocationCoordinate2D) {
//set zoom level
let zoomRegion = MKCoordinateRegion.init(center: coordinate, latitudinalMeters: 10000, longitudinalMeters: 10000)
//tells map to zoom animated
mapView.setRegion(zoomRegion, animated: true)
}
}
extension ViewController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("Did get Latest Location")
guard let latestLocation = locations.first else {return }
if currentCoordinate == nil{
zoomToLatestLocation(with: latestLocation.coordinate)
}
currentCoordinate = latestLocation.coordinate
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
print("The Status Changed")
if status == .authorizedAlways || status == .authorizedWhenInUse {
beginLocationUpdates(locationManager: manager)
}
}
}
But I will settle for any overlay working at all as a step in the right direction. Does anyone know of up to date code that will display an overlay on the map? Thanks.