Draw a circle of 1000m radius around users location in MKMapView

IosIos5MkmapviewMkannotationviewMkoverlay

Ios Problem Overview


(Using iOS 5 and Xcode 4.2)

I have an MKMapView and want to draw a circle of 1000m radius around the user location.

On the surface it would seem that implementing the mapView:viewForAnnotation: map view delegate method, and adding a custom MKAnnotationView for the users location, would be a perfect solution. It would look something like this:

- (MKAnnotationView *)mapView:(MKMapView *)mapView
            viewForAnnotation:(id <MKAnnotation>)annotation
{
    // If it's the user location, return my custom MKAnnotationView.
    if ([annotation isKindOfClass:[MKUserLocation class]]) {
        return myCustomAnnotationView;
    } else {
        return nil;
    }
}

However annotations on the map don't scale when you zoom in and out of the map.

So I tried adding an overlay (because overlays scale with the map), using the MKCircle class and setting its co-ordinates to the latest co-ordinates from my locationManger/map view delegate. However as the coordinate property of MKCircle is readonly, I'm having to remove the overlay then add a new one each time the user moves. Causing a noticeable flicker as it happens.

Is there any way to make an annotation scale seamlessly as the map view is scaled in and out? Or is there a good way to make an overlay move seamlessly with changes in the users location?

I would be very grateful for your help :)

Ios Solutions


Solution 1 - Ios

Try a custom overlay. Add this in viewDidLoad:

MKCircle *circle = [MKCircle circleWithCenterCoordinate:userLocation.coordinate radius:1000];
[map addOverlay:circle];

userLocation can be obtained by storing the MKUserLocationAnnotation as a property. Then, to actually draw the circle, put this in the map view's delegate:

- (MKOverlayRenderer *)mapView:(MKMapView *)map viewForOverlay:(id <MKOverlay>)overlay
{
    MKCircleRenderer *circleView = [[MKCircleRenderer alloc] initWithOverlay:overlay];
    circleView.strokeColor = [UIColor redColor];
    circleView.fillColor = [[UIColor redColor] colorWithAlphaComponent:0.4];
    return circleView;
}

Solution 2 - Ios

An updated version for iOS 8.0 using Swift.

import Foundation
import MapKit

class MapViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate{
    var locationManager: CLLocationManager = CLLocationManager()
    
    @IBOutlet var mapView: MKMapView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // We use a predefined location
        var location = CLLocation(latitude: 46.7667 as CLLocationDegrees, longitude: 23.58 as CLLocationDegrees)
        
        addRadiusCircle(location)
    }
    
    func addRadiusCircle(location: CLLocation){
        self.mapView.delegate = self
        var circle = MKCircle(centerCoordinate: location.coordinate, radius: 10000 as CLLocationDistance)
        self.mapView.addOverlay(circle)
    }
    
    func mapView(mapView: MKMapView!, rendererForOverlay overlay: MKOverlay!) -> MKOverlayRenderer! {
        if overlay is MKCircle {
            var circle = MKCircleRenderer(overlay: overlay)
            circle.strokeColor = UIColor.redColor()
            circle.fillColor = UIColor(red: 255, green: 0, blue: 0, alpha: 0.1)
            circle.lineWidth = 1
            return circle
        } else {
            return nil
        }
    }
}

Solution 3 - Ios

Swift 3/ Xcode 8 here:

func addRadiusCircle(location: CLLocation){
    if let poll = self.selectedPoll {
        self.mapView.delegate = self
        let circle = MKCircle(center: location.coordinate, radius: 10)
        self.mapView.add(circle)
    }
}

func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
    if overlay is MKCircle {
        let circle = MKCircleRenderer(overlay: overlay)
        circle.strokeColor = UIColor.red
        circle.fillColor = UIColor(red: 255, green: 0, blue: 0, alpha: 0.1)
        circle.lineWidth = 1
        return circle
    } else {
        return MKPolylineRenderer()
    }
}

Then call like so:

self.addRadiusCircle(location: CLLocation(latitude: YOUR_LAT_HERE, longitude: YOUR_LNG_HERE))

Solution 4 - Ios

Try to use the code from Apple Breadcrumb example

Solution 5 - Ios

I didn't understand benwad answer. So here is clearer answer:

It's pretty easy to add a circle. Conform to MKMapViewDelegate

@interface MyViewController : UIViewController <MKMapViewDelegate>
@property (weak, nonatomic) IBOutlet MKMapView *mapView;
@end

In viewDidLoad, Create a circle annotation and add it to the map:

CLLocationCoordinate2D center = {39.0, -74.00};

// Add an overlay
MKCircle *circle = [MKCircle circleWithCenterCoordinate:center radius:150000];
[self.mapView addOverlay:circle];

Then implement mapView:viewForOverlay: to return the view.

- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay
{
    MKCircleView *circleView = [[MKCircleView alloc] initWithOverlay:overlay];
    [circleView setFillColor:[UIColor redColor]];
    [circleView setStrokeColor:[UIColor blackColor]];
    [circleView setAlpha:0.5f];
    return circleView;
}

But if you want the circle to always be the same size, no matter the zoom level, you'll have to do something different. Like you say, in regionDidChange:animated:, get the latitudeDelta, then create a new circle (with a radius that fits into the width), remove the old one and add the new one.

Note from me: don't forget to connect mapview with your view controller delegate. Otherwise viewForOverlay won't be called.

Solution 6 - Ios

All I did is, After displaying the location on the map kit called the below function in the end.

@IBOutlet weak var mapView: GMSMapView!

var cirlce: GMSCircle!

override func viewDidLoad() {

    super.viewDidLoad()
    mapView.delegate = self
    circleview(redius: 5000) 

  }

//used this func to draw the circle

 func circleview(redius:Double) {

    let  circleCenter = CLLocationCoordinate2D(latitude: 13.3450223, longitude: 74.7512519)

    cirlce = GMSCircle(position: circleCenter, radius: redius)
    cirlce.fillColor = UIColor(red: 230.0/255.0, green: 230.0/255.0, blue: 250.0/255.0, alpha:1.0)
    cirlce.strokeColor = .blue
    cirlce.strokeWidth = 2
    cirlce.map = mapView
  }

Solution 7 - Ios

It's easy to add a circle. Conform to MKMapViewDelegate. follow the bellow steps,,,

Step 1 :

 CLLocationCoordinate2D center= {self.locationManager.location.coordinate.latitude, self.locationManager.location.coordinate.longitude};
// Add an overlay
MKCircle *circle= [MKCircle circleWithCenterCoordinate:center radius: 20000];//your distance like 20000(like meters)
[myMapView addOverlay:circle];

Step 2 :

 - (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay
 {
    MKCircleView *C_View = [[MKCircleView alloc] initWithOverlay:overlay];
    [C_View setFillColor:[UIColor lightGrayColor]];
    [C_View setStrokeColor:[UIColor blackColor]];
    [C_View setAlpha:0.5f];

    return C_View;
 }

Solution 8 - Ios

- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay

it is deprecated since iOS 4.0

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJon CoxView Question on Stackoverflow
Solution 1 - IosbenwadView Answer on Stackoverflow
Solution 2 - IosvladCovaliovView Answer on Stackoverflow
Solution 3 - IosthexandeView Answer on Stackoverflow
Solution 4 - IosShmidtView Answer on Stackoverflow
Solution 5 - IosRealNmaeView Answer on Stackoverflow
Solution 6 - Iosprajna kunderView Answer on Stackoverflow
Solution 7 - IosKupendiran iOSView Answer on Stackoverflow
Solution 8 - Iose aView Answer on Stackoverflow