I show several custom annotation views on an MKMapView, and when user taps one of them, I change the region to be centered on it:
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
if ([view.annotation isKindOfClass:[CustomAnnotation class]]) {
double miles = 2.5;
double scalingFactor = ABS(cos(2 * M_PI * lat / 360.0));
MKCoordinateSpan span;
span.latitudeDelta = miles/69.0;
span.longitudeDelta = miles/(scalingFactor * 69.0);
MKCoordinateRegion region;
region.span = span;
region.center = self.coordinates;
[self.mapView setRegion:region animated:YES];
}
}
I see that, when the annotation already was shown, more or less, in the center of the map, the callout is displayed, but it is not when I tap an annotation closer to the map's border and the region has to "move more". I tried to select the annotation after the region setting animation ends:
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
for (id annotation in self.mapView.annotations) {
if ([annotation isKindOfClass:[CustomAnnotation class]]) {
if (((CustomAnnotation *)annotation).id == self.selectedAnnotation.id) {
[self.mapView selectAnnotation:annotation animated:YES];
}
}
}
}
But the callout is neither shown. If I don't change programmatically the region when tapping, all callouts are shown. How could I solve this?
Thanks
Related
I've implemented - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation { method to change the default location of userLocation Annotation. Inside this method I've used:
if (annotation==(mapView.userLocation)) {
MKAnnotationView *myAnotation = [[MKAnnotationView alloc] init];
myAnotation.image = self.userPointImage.image;
myAnotation.centerOffset = CGPointMake(0, 250);
return myAnotation;
}
else
{
return nil;
}
Which successfully moves the default userLocation annotation to center bottom. But as I'm also using heading so when move my phone it is still rotating the map from center.
- (void)locationManager:(CLLocationManager *) manager didUpdateHeading:(CLHeading *) newHeading {
[self.mapView setUserTrackingMode:MKUserTrackingModeFollowWithHeading animated:true];
}
But the userLocation annotation is below. So how to do that?
UPDATE I found this question and tried applying it. But as I'm using heading so it crashes the app.
In my didUpdateUserLocation method I added [self moveCenterByOffset:CGPointMake(0, 200) from:userLocation.coordinate]; and this method is as follows:
- (CLLocationCoordinate2D)moveCenterByOffset:(CGPoint)offset from:(CLLocationCoordinate2D)coordinate
{
CGPoint point = [self.mapView convertCoordinate:coordinate toPointToView:self.mapView];
point.x += offset.x;
point.y += offset.y;
CLLocationCoordinate2D center = [self.mapView convertPoint:point toCoordinateFromView:self.mapView];
return center;
}
and then in my didUpdateUserLocation method I updated it as: MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance([self moveCenterByOffset:CGPointMake(0, -250) from:userLocation.coordinate], 800.0f, 200.0f); and [mapView setRegion:region animated:NO]; as I'm using heading so animation is set to NO. But now as I run the code it starts jerking between center and the new point.
MKCoordinateRegion region = mapClinicsView.region;
set 'region.center'
It will helps you to navigate your map center position
make sure 'region.center' and annotation center latitute and longitute is same
Apologies in advance for what must surely be so simple.
I want my map to zoom to a programmatically defined region surrounding the user's location. I've found tons of code where this is done via a button action, but I need it done automatically when the map loads. I'll post what I've tried here. Probably missing something very obvious. The meat of these both work as button actions, so I assume my issue is with my method code (first line of each).
Method 1: Using MKCoordinateSpanMake
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
float spanX = 0.00725;
float spanY = 0.00725;
MKCoordinateRegion region;
region.center.latitude = self.mapView.userLocation.coordinate.latitude;
region.center.longitude = self.mapView.userLocation.coordinate.longitude;
region.span = MKCoordinateSpanMake(spanX, spanY);
[self.mapView setRegion:region animated:YES];
}
Method 2: Using MKCoordinateRegionMakeWithDistance
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
MKUserLocation *userLocation = _mapView.userLocation;
MKCoordinateRegion region =
MKCoordinateRegionMakeWithDistance (
userLocation.location.coordinate, 3000, 3000);
[_mapView setRegion:region animated:YES];
}
As always, thanks so much for your time and advice.
Move to viewDidLoad:
- (void)viewDidLoad
{
MKUserLocation *userLocation = _mapView.userLocation;
MKCoordinateRegion region =[_mapView regionThatFits:MKCoordinateRegionMakeWithDistance (userLocation.location.coordinate, 3000, 3000)];
[_mapView setRegion:region animated:YES];
}
Hope that will help.
I am creating a map view in a view controller, using storyboard.
When I use the following code.
-(void) mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
CLLocationDistance distance = 1000;
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate,
distance,
distance);
MKCoordinateRegion adjusted_region = [self.mapView regionThatFits:region];
[self.mapView setRegion:adjusted_region animated:YES];
}
A point is plotted in San Francisco, CA, United States. The
userLocation coordinates are the predefined value in MapKit.h framework.
Now I create a
-(void) mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
CLLocationDistance distance = 1000;
CLLocationCoordinate2D myCoordinate;
myCoordinate.latitude = 13.04016;
myCoordinate.longitude = 80.243044;
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(myCoordinate,
distance,
distance);
MKCoordinateRegion adjusted_region = [self.mapView regionThatFits:region];
[self.mapView setRegion:adjusted_region animated:YES];
}
Here, the region is displayed having the coordinate in the center. But, no point is plotted at the coordinate position.
How to plot a point or annotation in that coordinate location?
Try this code inside of didUpdateUserLocation method
MKPointAnnotation* annotation = [[MKPointAnnotation alloc] init];
CLLocationCoordinate2D myCoordinate;
myCoordinate.latitude=13.04016;
myCoordinate.longitude=80.243044;
annotation.coordinate = myCoordinate;
[self.mapView addAnnotation:annotation];
Add this code in didUpdateUserLocation
MKAnnotation *annotation = [[MKAnnotation alloc] initWithCoordinate:CLLocationCoordinate2DMake(latitude, longitude)];
[myMap addAnnotation:annotation];
Try This..
//MAP VIEW Point
MKCoordinateRegion myRegion;
//Center
CLLocationCoordinate2D center;
center.latitude=latitude;
center.longitude=longitude;
//Span
MKCoordinateSpan span;
span.latitudeDelta=THE_SPAN;
span.longitudeDelta=THE_SPAN;
myRegion.center=center;
myRegion.span=span;
//Set our mapView
[MapViewC setRegion:myRegion animated:YES];
//Annotation
//1.create coordinate for use with the annotation
CLLocationCoordinate2D wimbLocation;
wimbLocation.latitude=latitude;
wimbLocation.longitude=longitude;
Annotation * myAnnotation= [Annotation alloc];
myAnnotation.coordinate=wimbLocation;
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
I have a MKMapView with a square overlay described as:
CLLocationCoordinate2D coordsBg[5]={
CLLocationCoordinate2DMake(31.750865,35.180882),
CLLocationCoordinate2DMake(31.740331,35.180882),
CLLocationCoordinate2DMake(31.740331,35.165452),
CLLocationCoordinate2DMake(31.750865,35.165452),
CLLocationCoordinate2DMake(31.750865,35.180882)
};
MKPolygon *bg=[MKPolygon polygonWithCoordinates:coordsBg count:5];
[map addOverlay:bg];
I wish to limit the user from scrolling outside of the overlay.
Can I limit the MKMapView scroll view for that? Or there is an other method?
Thanks
Shani
After Few hours of banging my head, I got to this solution that work great for me.
It mixes up :
This post: set the zoom level of an mkmapview
And This link: restrict mkmapview scrolling from #Anna Karenina comment to my question.
And This is my code:
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated
{
lastGoodMapRect = mapView.visibleMapRect;
lastGoodRegion = mapView.region;
}
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
if (manuallyChangingMapRect) {
manuallyChangingMapRect=NO;
return;
}
if( [mapView zoomLevel] > 16 )
{
[mapView setCenterCoordinate:lastGoodRegion.center zoomLevel:16 animated:YES];
}
MKMapRect visibleRect = mapView.visibleMapRect;
MKMapRect OverlayRect = bg.boundingMapRect;
MKMapRect intersectionRect = MKMapRectIntersection(visibleRect,OverlayRect);
//you can change the min and max zoom off course
if(!MKMapRectEqualToRect(visibleRect,intersectionRect)){
if( [mapView zoomLevel] < 15){
[mapView setCenterCoordinate:lastGoodRegion.center zoomLevel:15 animated:YES];
}else if( [mapView zoomLevel] > 16 )
{
[mapView setCenterCoordinate:lastGoodRegion.center zoomLevel:16 animated:YES];
}else{
manuallyChangingMapRect=YES;
[mapView setVisibleMapRect:lastGoodMapRect animated:YES];
}
}
}