How to change MKCircle radius on mapview with animation? - ios

I want to change the circle radius with animation like this:
https://www.youtube.com/watch?v=j0s5DUnEy3k
Here's my code:
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
if (locations != nil) {
userLocation = locations.firstObject;
CLLocationDegrees lat = 0.05;
CLLocationDegrees lon = 0.05;
MKCoordinateSpan span = MKCoordinateSpanMake(lat, lon);
CLLocationCoordinate2D location = CLLocationCoordinate2DMake(userLocation.coordinate.latitude, userLocation.coordinate.longitude);
MKCoordinateRegion region = MKCoordinateRegionMake(location, span);
[self.myMapView setRegion:region animated:true];
MKCircle *circle = [MKCircle circleWithCenterCoordinate:userLocation.coordinate radius:1000];
[self.myMapView addOverlay:circle];
}
}
I create user's location annotation and add a circle at user's location center
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id <MKOverlay>)overlay
{
MKCircleRenderer *circleView = [[MKCircleRenderer alloc] initWithOverlay:overlay];
circleView.strokeColor = [UIColor redColor];
circleView.fillColor = [[UIColor redColor] colorWithAlphaComponent:0.3];
circleView.lineWidth = 0.2;
return circleView;
}
and customized the circle at rendererForOverlay function
So, how can I change the circle radius with animation?
Anyone have idea to do this?

Related

Incorrect user location shown on MKMapView after scaling the map programmatically

I have MKMapView which have UserTrackingMode = MKUserTrackingModeFollow,
and I have adding a circle overlay to show a region of the certain diameter at user location.
Also user can change the diameter of the region so I want to scale the map to insure whole region/circle is shown on that portion of the map.
The problem I have now is that scaling the map number of times by setting region results in incorrect user location annotation - it is moved from the correct location.
I cannot understand why is that happens, I see in the debugger that the mapView.userLocation property have correct coordinates.
But once new update is happens or I move the map manually - the annotation jumps to the correct place.
This is the code:
- (void)addCircleWithRadius:(double)radius andCoordinate:(CLLocationCoordinate2D)coordinate
{
_regionCircle = [MKCircle circleWithCenterCoordinate:coordinate radius:radius];
[_regionCircle setTitle:#"Region"];
MKCoordinateRegion region;
region.center.latitude = coordinate.latitude;
region.center.longitude = coordinate.longitude;
region.span.latitudeDelta = 0.00002 * _regionCircle.radius;
region.span.longitudeDelta = 0.00002 * _regionCircle.radius;
MKCoordinateRegion adjustedRegion = [self.mapView regionThatFits: region];
[self.mapView setRegion:adjustedRegion animated:TRUE];
_circleView = nil;
[self.mapView addOverlay:_regionCircle];
}
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
if(!_circleView)
{
_circleView = [[MKCircleView alloc] initWithCircle:overlay];
_circleView.strokeColor = [UIColor blueColor];;
_circleView.fillColor = [UIColor blueColor];
_circleView.alpha = 0.25;
_circleView.lineWidth = 2.0;
}
return _circleView;
}
- (IBAction)regionSliderValueChanged:(id)sender
{
[self updateRadiusCircle];
}
- (void) updateRadiusCircle
{
[self.mapView removeOverlays:self.mapView.overlays];
CLLocationCoordinate2D myCoordinate = {_currentLocation.coordinate.latitude, _currentLocation.coordinate.longitude};
[self addCircleWithRadius:self.radiusSlider.value andCoordinate:myCoordinate];
}
I have published the video on YouTube to better understand the issue.
https://www.youtube.com/watch?v=474gdjkGwJA

How to overlay a circle on an iOS map

I've got a radius and a location.
This is how I'm trying to get the bounding rectangle of the circle.
- (MKMapRect)boundingMapRect{
CLLocationCoordinate2D tmp;
MKCoordinateSpan radiusSpan = MKCoordinateRegionMakeWithDistance(self.coordinate, 0, self.radius).span;
tmp.latitude = self.coordinate.latitude - radiusSpan.longitudeDelta;
tmp.longitude = self.coordinate.longitude - radiusSpanSpan.longitudeDelta;
MKMapPoint upperLeft = MKMapPointForCoordinate(tmp);
MKMapRect bounds = MKMapRectMake(upperLeft.x, upperLeft.y, self.radius * 2, self.radius * 2);
return bounds;
}
MKMapRectMake(...) seems to want width and height measured in Map points. How do I convert the radius to that?
In the end I'm rendering it like this:
MKMapRect theMapRect = [self.overlay boundingMapRect];
CGRect theRect = [self rectForMapRect:theMapRect];
CGContextAddEllipseInRect(ctx, theRect);
CGContextFillPath(ctx);
The radius doesn't seem to equal meters on the map in the end and also the distance doesn't seem to be measured correctly. How to do it right?
I would be really thankful for every hint.
You should be using MKCircle instead. Do something like:
CLLocationDistance fenceDistance = 300;
CLLocationCoordinate2D circleMiddlePoint = CLLocationCoordinate2DMake(yourLocation.latitude, yourLocation.longitude);
MKCircle *circle = [MKCircle circleWithCenterCoordinate:circleMiddlePoint radius:fenceDistance];
[yourMapView addOverlay: circle];
And adopt the MKMapViewDelegate Method below and do something like this:
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay
{
MKCircleView *circleView = [[[MKCircleView alloc] initWithCircle:(MKCircle *)overlay] autorelease];
circleView.fillColor = [[UIColor redColor] colorWithAlphaComponent:0.9];
return circleView;
}
For iOS7 :
Same as tdevoy in viewDidLoad :
CLLocationDistance fenceDistance = 300;
CLLocationCoordinate2D circleMiddlePoint = CLLocationCoordinate2DMake(yourLocation.latitude, yourLocation.longitude);
MKCircle *circle = [MKCircle circleWithCenterCoordinate:circleMiddlePoint radius:fenceDistance];
[yourMapView addOverlay: circle];
But the delegate method (because mapView:viewForOverlay: is deprecated) :
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id < MKOverlay >)overlay
{
MKCircleRenderer *circleR = [[MKCircleRenderer alloc] initWithCircle:(MKCircle *)overlay];
circleR.fillColor = [UIColor greenColor];
return circleR;
}

Draw Rectangle on the MapView

My application gets data in the following coverage area. I would like to use these boundary values to draw rectangle on the map. Do you have any idea? Thanks in advance
Left Upper Boundary: 30.439217,-95.899668;
Right Upper Boundary: 30.443953,-94.685679;
Left Buttom boundary: 28.930662,-95.908595;
Right Buttom Boundary: 28.930061,-94.690486;
if you wanna draw something basic with lines u can use this MKPolyline
Try the code below, Make sure your delegate is connected with your mapview object
- (void) drawRect
{
CLLocation *coordinates1 = [[CLLocation alloc] initWithLatitude:30.439217 longitude:-95.899668];
CLLocation *coordinates2 = [[CLLocation alloc] initWithLatitude:30.443953 longitude:-94.685679];
CLLocation *coordinates3 = [[CLLocation alloc] initWithLatitude:28.930061 longitude:-94.690486];
CLLocation *coordinates4 = [[CLLocation alloc] initWithLatitude:28.930662 longitude:-95.908595];
NSMutableArray *locationCoordinates = [[NSMutableArray alloc] initWithObjects:coordinates1,coordinates2,coordinates3,coordinates4,coordinates1, nil];
int numberOfCoordinates = [locationCoordinates count];
CLLocationCoordinate2D coordinates[numberOfCoordinates];
for (NSInteger i = 0; i < [locationCoordinates count]; i++) {
CLLocation *location = [locationCoordinates objectAtIndex:i];
CLLocationCoordinate2D coordinate = location.coordinate;
coordinates[i] = coordinate;
}
MKPolyline *polyLine = [MKPolyline polylineWithCoordinates:coordinates count:numberOfCoordinates];
[self.myMapView addOverlay:polyLine];
}
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay {
MKPolylineView *polylineView = [[MKPolylineView alloc] initWithPolyline:overlay];
polylineView.strokeColor = [UIColor redColor];
polylineView.lineWidth = 1.0;
return polylineView;
}
UPDATE: Here's the swift version of the drawRect function
func drawRect() {
let coordinates1 = CLLocation(latitude: 30.439217, longitude: -95.899668)
let coordinates2 = CLLocation(latitude: 30.443953, longitude: -94.685679)
let coordinates3 = CLLocation(latitude: 28.930061, longitude: -94.690486)
let coordinates4 = CLLocation(latitude: 28.930662, longitude: -95.908595)
let locationCoordinates = [coordinates1,coordinates2,coordinates3,coordinates4,coordinates1]
let coordinates = locationCoordinates.map { $0.coordinate }
let polyLine = MKPolyline(coordinates: coordinates, count: coordinates.count)
mapView.addOver(polyLine)
}
replace the
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay (deprecated)
with
func mapView(mapView: MKMapView, rendererForOverlay overlay: MKOverlay) -> MKOverlayRenderer
Since you've asked a general question I can only give you a general hint at the answer.
MKMapView has a method convertCoordinate:toPointToView: which turns a coordinate to a point in the view. You can use this to draw on an overlay.
First:
#import <QuartzCore/QuartzCore.h>
Then do this where you want:
CLLocationCoordinate2D koor = CLLocationCoordinate2DMake(30.439217,-95.899668);
CLLocationCoordinate2D koor2 = CLLocationCoordinate2DMake(30.443953,-94.685679);
CLLocationCoordinate2D koor3 = CLLocationCoordinate2DMake(28.930662,-95.908595);
CGPoint point1 = [mapView convertCoordinate:koor toPointToView:mapView];
CGPoint point2 = [mapView convertCoordinate:koor2 toPointToView:mapView];
CGPoint point3 = [mapView convertCoordinate:koor3 toPointToView:mapView];
UIView *someView = [[UIView alloc]initWithFrame:CGRectMake(point1.x, point1.y, point2.x-point1.x, point3.y-point1.y)];
[self viewBicimle:someView];
[someView setBackgroundColor:[UIColor clearColor]];
[someView.layer setBorderColor:[[[UIColor blackColor] colorWithAlphaComponent:1.0] CGColor]];
[someView.layer setBorderWidth:1.0];
[mapView addSubview:someView];
[someView release];
But this will only work for an immovable some MapView. When you move the map it will slide...

Circle Overlay is not showing on map

I am trying to add a circle overlay to a map, but it is not appearing:
- (void) displayOverlayOnMap:(double) lat andlng: (double) lng
{
CLLocationCoordinate2D bostonCoord = CLLocationCoordinate2DMake(lat,lng);
//add MKCircle overlay...
MKCircle *circle = [MKCircle circleWithCenterCoordinate:bostonCoord radius:1000];
[self.mapView addOverlay:circle];
}
Any body have a clue why it's not showing?
here is an example.. you can also find one using polygons on apple's sites: https://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/LocationAwarenessPG/AnnotatingMaps/AnnotatingMaps.html#//apple_ref/doc/uid/TP40009497-CH6-SW15
or you can use this example
Create overlay from user interaction on MKMapView?
- (void)handleLongPress:(UIGestureRecognizer *)gestureRecognizer
{
if (gestureRecognizer.state != UIGestureRecognizerStateBegan)
return;
CGPoint touchPoint = [gestureRecognizer locationInView:mapView];
CLLocationCoordinate2D touchMapCoordinate = [mapView convertPoint:touchPoint toCoordinateFromView:mapView];
//add pin where user touched down...
MKPointAnnotation *pa = [[MKPointAnnotation alloc] init];
pa.coordinate = touchMapCoordinate;
pa.title = #"Hello";
[mapView addAnnotation:pa];
[pa release];
//add circle with 5km radius where user touched down...
MKCircle *circle = [MKCircle circleWithCenterCoordinate:touchMapCoordinate radius:5000];
[mapView addOverlay:circle];
}
-(MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id)overlay
{
MKCircleView* circleView = [[[MKCircleView alloc] initWithOverlay:overlay] autorelease];
circleView.fillColor = [UIColor redColor];
return circleView;
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
static NSString *AnnotationIdentifier = #"Annotation";
MKPinAnnotationView* pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:AnnotationIdentifier];
if (!pinView)
{
pinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier] autorelease];
pinView.pinColor = MKPinAnnotationColorGreen;
pinView.animatesDrop = YES;
}
else
{
pinView.annotation = annotation;
}
return pinView;
}
Use the code
CLLocationDistance radiusInMeters = 1000;
MKCircle *circle = [MKCircle circleWithCenterCoordinate:bostonCoord radius:radiusInMeters];
Instead of
MKCircle *circle = [MKCircle circleWithCenterCoordinate:bostonCoord radius:1000];
It worked for me.

MKCircle is not updating radius but it's translating

I've to draw an MKCicle into an MKMapView. Then I've to re-draw it when user, through a slider, change the radius. I remove it and I re-create it, re-adding it to the map.
But instead of do what I'm expecting, I see the MKCircle translating over the map, maintaining the same size.
Here's my code:
- (MKOverlayView *)mapView:(MKMapView *)map viewForOverlay:(id)overlay
{
MKOverlayView* overlayView = nil;
if(overlay == self.circle)
{
//if we have not yet created an overlay view for this overlay, create it now.
if(nil == self.circleView)
{
self.circleView = [[[MKCircleView alloc] initWithCircle:self.circle] autorelease];
self.circleView.fillColor = [UIColor blueColor];
self.circleView.strokeColor = [UIColor blueColor];
self.circleView.alpha = 50;
self.circleView.lineWidth = 2;
}
overlayView = self.circleView;
}
return overlayView;
}
-(void)drawPolygonWithLocation
{
[self.mapView removeOverlay: self.circle];
MKCoordinateRegion region;
region.center.latitude = self.geofenceLocation.latitude;
region.center.longitude = self.geofenceLocation.longitude;
region.span.latitudeDelta = 0.005;
region.span.longitudeDelta = 0.005;
MKCoordinateRegion adjustedRegion = [self.mapView regionThatFits: region];
[self.mapView setRegion:adjustedRegion animated:TRUE];
self.radius = (double)(slRadius.value);
NSLog(#"Raggio: %f", self.radius);
NSLog(#"Lat: %f, Lon: %f", region.center.latitude, region.center.longitude);
self.circle = [MKCircle circleWithCenterCoordinate:self.geofenceLocation.coordinate radius: self.radius];
NSLog(#"CIRCLE: radius %f Lat: %f, Lon: %f", self.circle.radius, self.circle.coordinate.latitude, self.circle.coordinate.longitude);
[self.mapView addOverlay:self.circle];
}
-(IBAction)updateRadius:(id)sender
{
[self drawPolygonWithLocation];
}
The NSLog is writing into the console right values, the center doesn't change and the radius changes according to the user input.
But, again, the MKCircle translates going on the north-west.
Thanks in advance,
Samuel Rabini
Fixed.
I just add
self.circleView = nil;
before the
[self.mapView addOverlay:self.circle];
in this way it works fine.
Samuel

Resources