64

(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 :)

Jon Cox
  • 10,622
  • 22
  • 78
  • 123
  • 7
    I think a custom overlay and overlay view is what you'll need (which is what @Flink seems to be implying). However, an Apple example closer to your requirement is the LocationReminders app from WWDC 2010. If you're a registered developer, you can find it [here](http://connect.apple.com/cgi-bin/WebObjects/MemberSite.woa/wa/getSoftware?code=y&source=x&bundleID=20645). It custom draws a circle overlay whose size and position can change dynamically. –  Jan 30 '12 at 02:23
  • Thanks for the link, sounds exactly like the example I need. Plus I am a registered developer, so that's handy :) – Jon Cox Jan 30 '12 at 02:59
  • Link is broken, but I found this on github: https://github.com/master-nevi/WWDC-2010/tree/master/LocationReminders – foson Dec 30 '17 at 23:21

8 Answers8

81

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;
}
Léo Natan
  • 56,823
  • 9
  • 150
  • 195
benwad
  • 6,414
  • 10
  • 59
  • 93
  • move the circle whenever the userlocation changes – Daij-Djan Jun 04 '13 at 12:11
  • how do we move the circle? we would need to create a new MKCircle every time it moves? – yuf Dec 12 '13 at 00:59
  • Needs updating for iOS 7! – Hyperbole Mar 27 '14 at 01:35
  • 18
    Note that `MKOverlayView` and `MKCircleView` are deprecated in iOS 7 (to @Hyperbole's point). Use [`MKOVerlayRenderer`](https://developer.apple.com/library/ios/documentation/MapKit/Reference/MKOverlayRenderer_class/Reference/Reference.html) and [`MKCircleRenderer`](https://developer.apple.com/library/ios/documentation/MapKit/Reference/MKCircleRenderer_class/Reference/Reference.html#//apple_ref/occ/cl/MKCircleRenderer) instead. – ericsoco Apr 16 '14 at 06:50
  • 1
    You also need to use the MKMapViewDelegate protocol for this to work – vladCovaliov Sep 25 '14 at 12:18
50

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
        }
    }
}
Ben Trengrove
  • 8,191
  • 3
  • 40
  • 58
vladCovaliov
  • 4,333
  • 2
  • 43
  • 58
25

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))
Naveed Ahmad
  • 6,627
  • 2
  • 58
  • 83
thexande
  • 1,645
  • 16
  • 23
3

Try to use the code from Apple Breadcrumb example

Shmidt
  • 16,436
  • 18
  • 88
  • 136
2

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.

RealNmae
  • 630
  • 9
  • 20
1

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
  }
Alex Riabov
  • 8,655
  • 5
  • 47
  • 48
0

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;
 }
Kupendiran iOS
  • 217
  • 2
  • 5
0
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay

it is deprecated since iOS 4.0

Jagat Dave
  • 1,643
  • 3
  • 23
  • 30
e a
  • 103
  • 9