How to create MKCircle in Swift?

2019-02-17 12:05发布

问题:

Iv been searching all around for a good explanation of how to make an MKCircle annotation for the MapView using Swift 2.0 but I cant seem to find an adequate explanation. Can someone post some example code showing how to create the MKCircle annotation? Here is the code i'm using to make the map and get the coordinate.

let address = self.location

let geocoder = CLGeocoder()

    geocoder.geocodeAddressString(address, completionHandler: {(placemarks, error) -> Void in
        if((error) != nil){
            print("Error", error)
        }
        if let placemark = placemarks?.first {
            let coordinates:CLLocationCoordinate2D = placemark.location!.coordinate

            self.locationCoordinates = coordinates
            let span = MKCoordinateSpanMake(0.005, 0.005)
            let region = MKCoordinateRegion(center: self.locationCoordinates, span: span)
            self.CIMap.setRegion(region, animated: true)

            let annotation = MKPointAnnotation()
            annotation.coordinate = self.locationCoordinates
            self.CIMap.addAnnotation(annotation)

            self.CIMap.layer.cornerRadius = 10.0

            self.CIMap.addOverlay(MKCircle(centerCoordinate: self.locationCoordinates, radius: 1000))
        }
    })

回答1:

Will show step wise approach about how to create a circular overlay on map view using swift 3 with xcode 8.3.3

In your main storyboard file drag map kit view on to the scene(view) of storyboard and create outlet for the same, here i created mapView. Also you want to create overlay dynamically whenever you go for long press on map, so drag Long Press Gesture Recognizer on to the mapView from object libary and then create action method for the same, here i had created addRegion() for the same.

  1. create a global constant for CLLocationManager class so that it can be accessed in every function. And in your viewDidLoad method, add some code for getting authorization from the user.

        import UIKit  
        import MapKit
    
        class ViewController: UIViewController {
    
    
            @IBOutlet var mapView: MKMapView!
            let locationManager = CLLocationManager()
    
        override func viewDidLoad() {  
                super.viewDidLoad()
    
                locationManager.delegate = self
                locationManager.requestAlwaysAuthorization()
                locationManager.requestWhenInUseAuthorization()
                locationManager.desiredAccuracy = kCLLocationAccuracyBest
                locationManager.startUpdatingLocation()
    
            }
    
  2. Add code for generating a circular region whenever you do long press gesture recognizer in your long press gesture recognizer action method addRegion().

        @IBAction func addRegion(_ sender: Any) {  
                print("addregion pressed")  
                guard let longPress = sender as? UILongPressGestureRecognizer else {return}
    
                let touchLocation = longPress.location(in: mapView)
                let coordinates = mapView.convert(touchLocation, toCoordinateFrom: mapView)
                let region = CLCircularRegion(center: coordinates, radius: 5000, identifier: "geofence")
                mapView.removeOverlays(mapView.overlays)
                locationManager.startMonitoring(for: region)
                let circle = MKCircle(center: coordinates, radius: region.radius)
                mapView.add(circle)
    
            }
    

Still you won't see circle physically on the map until you render circle on map. for this you need to implement delegate of mapviewdelegate.

        func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {}
  1. To make code look more cleaner you can create extension after last brace where your class ends. One extension contains code for CLLocationManagerDelegate and other for MKMapViewDelegate.

        extension ViewController: CLLocationManagerDelegate {
            func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
                locationManager.stopUpdatingLocation()
                mapView.showsUserLocation = true
            }
        }
    

you should call locationManager.stopUpdatingLocation() in delegate method so that your battery does not drain out.

        extension ViewController: MKMapViewDelegate {
            func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
                guard let circelOverLay = overlay as? MKCircle else {return MKOverlayRenderer()}

                let circleRenderer = MKCircleRenderer(circle: circelOverLay)
                circleRenderer.strokeColor = .blue
                circleRenderer.fillColor = .blue
                circleRenderer.alpha = 0.2
                return circleRenderer
            }
        }

Here we are making the actual circle on the screen.

Final code should look like this.

import UIKit
import MapKit

class ViewController: UIViewController {


    @IBOutlet var mapView: MKMapView!
    let locationManager = CLLocationManager()

    override func viewDidLoad() {
        super.viewDidLoad()

        locationManager.delegate = self
        locationManager.requestAlwaysAuthorization()
        locationManager.requestWhenInUseAuthorization()
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.startUpdatingLocation()

    }

    // MARK: Long Press Gesture Recognizer Action Method

    @IBAction func addRegion(_ sender: Any) {
        print("addregion pressed")
        guard let longPress = sender as? UILongPressGestureRecognizer else {return}

        let touchLocation = longPress.location(in: mapView)
        let coordinates = mapView.convert(touchLocation, toCoordinateFrom: mapView)
        let region = CLCircularRegion(center: coordinates, radius: 5000, identifier: "geofence")
        mapView.removeOverlays(mapView.overlays)
        locationManager.startMonitoring(for: region)
        let circle = MKCircle(center: coordinates, radius: region.radius)
        mapView.add(circle)

    }

}

extension ViewController: CLLocationManagerDelegate {
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        locationManager.stopUpdatingLocation()
        mapView.showsUserLocation = true
    }
}

extension ViewController: MKMapViewDelegate {
    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
        guard let circelOverLay = overlay as? MKCircle else {return MKOverlayRenderer()}

        let circleRenderer = MKCircleRenderer(circle: circelOverLay)
        circleRenderer.strokeColor = .blue
        circleRenderer.fillColor = .blue
        circleRenderer.alpha = 0.2
        return circleRenderer
    }
}


回答2:

First you need to add MKMapViewDelegate to the class defenition.

 mapView.delegate = self 

Set the maps delegate to self in your viewDidLoad.

Setting the annotation

mapView.addOverlay(MKCircle(centerCoordinate: CLLocationCoordinate2D, radius: CLLocationDistance))

mapView rendererForOverlay should now be called in the mapViews delegate and there you get to draw it

func mapView(mapView: MKMapView, rendererForOverlay overlay: MKOverlay) -> MKOverlayRenderer {
    if let overlay = overlay as? MKCircle {
        let circleRenderer = MKCircleRenderer(circle: overlay)
        circleRenderer.fillColor = UIColor.blueColor()
        return circleRenderer
    }
}

Also, you need to import MapKit for it all to compile



回答3:

An overlay is merely a set of numbers. The thing that is visible in the map view is an overlay renderer. You must implement mapView:rendererForOverlay: to supply the overlay renderer; otherwise, you will see nothing.