I put a map into my iOs app and I setted it in this way:
- (void)viewDidLoad {
[super viewDidLoad];
CLLocationCoordinate2D cord = {.latitude = 44.508473, .longitude = 11.375828};
[self.myMap setRegion:MKCoordinateRegionMake(cord, MKCoordinateSpanMake(.005, .005)) animated:YES];
AddressAnnotation * annotazione = [[AddressAnnotation alloc] init];
[annotazione setCoordinate:cord];
[self.myMap addAnnotation:annotazione];
}
and AddressAnnotation.m:
- (void)setCoordinate:(CLLocationCoordinate2D)coord {
coordinate = coord;
}
It works but first time I open map's view it shows a zone near the Antartica sea (pin head to coordinates but map shows Antartic sea zones) and closing and reopening map's view it shows exactly my pin.
How can I show map zoomed on Pin at first opening?
Thank you so much!
There's nothing wrong with this code. I would probably just define a coordinate property for your AddressAnnotation and let the compiler synthesize the appropriate setter and get rid of the custom setter, though that's probably unrelated to the problem you describe ... It's just easier to do it that way, it ensures that the annotation's coordinate will conform to KVO, etc.
I might suggest that you define your view controller to be the delegate of the map view and then implement regionDidChangeAnimated:
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
NSLog(#"%s %f, %f %d", __FUNCTION__, mapView.region.center.latitude, mapView.region.center.longitude, animated);
}
It might be useful to know what the region is getting set to and maybe you can reverse engineer what's going on.
But, bottom line, the problem is unrelated to the code you included in your question and the issue undoubtedly rests elsewhere.
By doing this in your project, I saw the following log:
2013-03-30 23:11:12.326 iBo[25408:c07] -[POIMapController mapView:regionDidChangeAnimated:] -47.422141, 0.000000 0
2013-03-30 23:11:12.328 iBo[25408:c07] -[POIMapController mapView:regionDidChangeAnimated:] 44.508473, 11.375828 0
2013-03-30 23:11:12.328 iBo[25408:c07] -[POIMapController mapView:regionDidChangeAnimated:] -47.422141, 0.000000 0
2013-03-30 23:11:12.329 iBo[25408:c07] -[POIMapController mapView:regionDidChangeAnimated:] -47.422141, 0.000000 0
So, clearly your setting the region is taking place, but there's something else which is resetting the region after that happens. Doing a little playing around, I discovered that this behavior only manifests itself when using auto layout. If you turn off auto layout, this behavior goes away and it works like you'd expect.
Alternatively, I noticed that if you moved your code to set the region out of viewDidLoad (which is quite early in the view creation process (after the view are created, but before they appear), and put it in viewDidAppear, it works.
Related
if the user zooms out on a MKMapView, i want MKAnnotations which are near to each other automatically grouped into one "group" annotation.
if the user zooms back in, the "group" annotation should be split again to the unique/original annotations.
apple does this already in the iOS 4 Photos.app
is there a common, "predefined" way to do this?
Its normal working with more than 1500 annotations on the map:
-(void)mapView:(MKMapView *)mapView_ regionDidChangeAnimated:(BOOL)animated
{
NSMutableSet * coordSet = [[NSMutableSet alloc] init];
for(id<MKAnnotation> an in mapView_.annotations)
{
if([an isKindOfClass:[MKUserLocation class]])
continue;
CGPoint point = [mapView_ convertCoordinate:an.coordinate toPointToView:nil];
CGPoint roundedPoint;
roundedPoint.x = roundf(point.x/10)*10;
roundedPoint.y = roundf(point.y/10)*10;
NSValue * value = [NSValue valueWithCGPoint:roundedPoint];
MKAnnotationView * av = [mapView_ viewForAnnotation:an];
if([coordSet containsObject:value])
{
av.hidden = YES;
}
else
{
[coordSet addObject:value];
av.hidden = NO;
}
}
[coordSet release];
}
That's a brilliant idea. I'm working on a similar app, I hope you don't mind if I als implement the concept :).
To answer your question to the best of my own ability, no, I don't think there is a predefined way to do this.
The best way I can think of to do it (after looking at the iOS4 photos app), is to make use of the mapView:regionDidChangeAnimated: delegate method. Any time the user scrolls/zooms, this method will be called.
Inside that method, you could have some quick geometry math to determine whether your points are "close enough" to consider merging. Once they're "merged", you'd remove one or both annotations, and put another annotation back in the same place that is a reference to both (you could make an AnnotationCluster class very easily that could conform to MKAnnotation but also hold an NSArray of annotations, and also contain methods for "breaking out" or "absorbing" other annotations and/or AnnotationCluster instances, etc).
When I say "quick geometry math", I mean the distance of the two points relative to the span of the map, and taking their relative distance as a percentage of the span of the whole map.
Where that would get tricky is if you had hundreds of annotations, as I can't off-hand think of a good way to implement that w/o a double loop.
What do you reckon?
This project does something interesting. Though, have a look at reported issues before changing too many things in your code. Because it could be not good enough for your needs yet.
I personnaly ended up implementing this
I'm desperately looking for a workaround to the well documented bug in MapKit in iOS6 that makes MKUserTrackingModeFollowWithHeading effectively unusable at higher magnifications:
There is a very simple example project [here].(https://dl.dropboxusercontent.com/u/316978/MapKitBug.zip)
Steps to reproduce:
Tap the MKUserTrackingModeButton to zoom in to your location.
Tap to zoom in closer 2 or 3 times.
Tap MKUserTrackingModeButton to select MKUserTrackingModeFollowWithHeading
Issues:
This mode will not 'stick' and almost always exits after a matter of seconds (1-20).
The Blue 'Your Location' Annotation 'vibrates' and seems to move slightly from its central position whilst it's in MKUserTrackingModeFollowWithHeading.
Note that this is increasingly a problem as you zoom in. At the default magnification (which you are taken to when first tapping the MKUserTrackingModeButton Button, it is not so much of a problem.
An obvious workaround would be to limit zoom level, but unfortunately I need full zoom in my application.
I , too, got frustrated with this extremely annoying bug.
I have a deadline just around the corner, so I can't spend a lot of time trying to implement a workaround.
I had managed to get it to stay in MKUserTrackingModeFollowWithHeading at max zoom, but the User Location annotation "pin" still jittered around quite heavily, and in some edge cases, it was still canceling back into MKUserTrackingModeFollow.
What I did, initially, was to force a correction using BOOL flags in the regionDidChangeAnimated: delegate method, like so:
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
NSLog(#"regionWillChangeAnimated:");
}
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
NSLog(#"regionDidChangeAnimated:");
[self forceCorrectUserTrackingMode];
}
- (void)forceCorrectUserTrackingMode {
if (shouldFollowWithHeading == YES && ([mapView userTrackingMode] != MKUserTrackingModeFollowWithHeading) ) {
NSLog(#"FORCE shouldFollowWithHeading! - setUserTrackingMode:MKUserTrackingModeFollowWithHeading");
[self.mapView setUserTrackingMode:MKUserTrackingModeFollowWithHeading animated:YES];
} else if (shouldFollowWithHeading == NO && ([mapView userTrackingMode] != MKUserTrackingModeNone) ) {
NSLog(#"FORCE should NOT FollowWithHeading - setUserTrackingMode:MKUserTrackingModeNone");
[self.mapView setUserTrackingMode:MKUserTrackingModeNone animated:YES];
}
}
This actually got me pretty close, but it wasn't reliable enough, and like I said, I had to think about prioritizing other features for my deadline, so this is what I ended up doing:
First, I grabbed this code for a zoom category on MKMapKit: http://troybrant.net/blog/2010/01/set-the-zoom-level-of-an-mkmapview/
Next, I included this method that a visitor provided in that blog's comments:
- (int) getZoomLevel {
return 21 – round(log2(mapView.region.span.longitudeDelta * MERCATOR_RADIUS * M_PI / (180.0 * mapView.bounds.size.width)));
}
Finally, a little trial and error testing the zoom levels vs. the occurrence of the bug led me to the following "workaround":
CLLocationCoordinate2D userLocation_CenterCoordinate = CLLocationCoordinate2DMake([locationManager location].coordinate.latitude, [locationManager location].coordinate.longitude);
int currentZoomLevel = [MKMapView getZoomLevelForMapView:mapView];
int newZoomLevel = 17;
if (currentZoomLevel > 17) {
NSLog(#"Adjusting mapView's zoomLevel from [%d] to [%d], also centering on user's location", currentZoomLevel, newZoomLevel);
[mapView setCenterCoordinate:userLocation_CenterCoordinate zoomLevel:newZoomLevel animated:NO];
} else {
NSLog(#"Centering on user's location, not adjusting zoom.");
[mapView setCenterCoordinate:userLocation_CenterCoordinate animated:NO];
}
Opened a TSI, and Apple confirmed that there is no workaround. I wonder if they'll have fixed it in 7 …
I have been working on the same app for a number of months, and this is a new problem. I am wondering if there has been a change in the server side of the Apple Map data. Here's the issue:
My app (at times) wants to set an MKMapView region to the most fully zoomed in value possible around a particular location. To do this, I do something like:
self.map.mapType = MKMapTypeHybrid;
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(CLLocationCoordinate2DMake(item.lat, item.lng), 1.0, 1.0);
[self.map setRegion:region animated:NO];
Regardless of where item's coordinate is, I get the gridded "no satellite images" background. This does not seem to be related to available satellite imagery, as it behaves consistently across many areas of the US.
I am aware that setRegion:animated: may adjust the region after the fact. And I am aware the a 1m square is an unreasonably small area to attempt to show on a fairly large map. So, I've tried
[self.map setRegion:[self.map regionsThatFits:region] animated:NO];
Setting animated:YES does seem to prevent this from occurring, but I do not want to animate these changes.
A few more observations:
If I zoom out just 1 or 2 pixels, the map imagery appears.
Attempting to implement the map delegate method: – mapViewDidFailLoadingMap:withError: does not help. It never is called.
This seems to be new. The working version I have of the app in the app store, now exhibits similar issues.
I have seen this happen in other popular apps recently.
Any thoughts on a solution to this, or confirmation that it is a systemic problem?
//fix for ios6
if (region.span.latitudeDelta < .0005f)
region.span.latitudeDelta = .0005f;
if (!region.span.longitudeDelta < .0005f)
region.span.longitudeDelta = .0005f;
Make sure your region span for lat/lon isn't set too low and it will clear up.
I ended up subclassing MKMapView and overriding setRegion:. I've created a sample app in Github if anyone is interested in seeing the issue in action, or my solution:
https://github.com/DeepFriedTwinkie/iOS6MapZoomIssue
My setRegion: method looks like this:
- (void) setRegion:(MKCoordinateRegion)region animated:(BOOL)animated {
#try {
// Get the zoom level for the proposed region
double zoomLevel = [self getFineZoomLevelForRegion:region];
// Check to see if any corrections are needed:
// - Zoom level is too big (a very small region)
// - We are looking at satellite imagery (Where the issue occurs)
// - We have turned on the zoom level protection
if (zoomLevel >= (MAX_GOOGLE_LEVELS-1) && self.mapType != MKMapTypeStandard && self.protectZoomLevel) {
NSLog(#"setRegion: Entered Protected Zoom Level");
// Force the zoom level to be 19 (20 causes the issue)
MKCoordinateRegion protectedRegion = [self coordinateRegionForZoomLevel:MAX_GOOGLE_LEVELS-1.0 atCoordinate:region.center];
[super setRegion:protectedRegion animated:animated];
} else {
[super setRegion:region animated:animated];
}
}
#catch (NSException *exception) {
[self setCenterCoordinate:region.center];
}
}
I'm trying to setup an offline map in an iPhone app, but the result is not very good.
I'm using the route-me framework, I've got an offline file .db (created by tiles2sqlite) and the map view is constrained with coordinates (using setConstraintsSW:NE:).
My problem is appearing when zooming out (pinch gesture), this error message "Zooming will move map out of bounds: no zoom" is always present and it's very difficult to zoom out when you are not near the real center of the map.
Is there a solution to have the same result as in Offmaps (iOS app) where the map has a nice scrollview behavior?
Cheers.
Cyril
I had to edit RMMapView.m source code to make a quick fix. Find - (void)zoomByFactor: (float) zoomFactor near:(CGPoint) center animated:(BOOL)animated method (near line 300). It has constrain logic, I turned it off:
- (void)zoomByFactor: (float) zoomFactor near:(CGPoint) center animated:(BOOL)animated
{
if ( _constrainMovement && false ) // turn constraint checks off
{
//check that bounds after zoom don't exceed map constraints
//the logic is copued from the method zoomByFactor,
float _zoomFactor = [self.contents adjustZoomForBoundingMask:zoomFactor];
float zoomDelta = log2f(_zoomFactor);
...
}
...
}
Now map is zoomed smoothly, but this fix could have side effects.
Instead you can use of setting setConstraintsSW:NE: we can set RMMapview as,
RMDBMapSource *mapSrc = [[[RMDBMapSource alloc] initWithPath:#"mapDB.sqlite"] autorelease];
[[RMMapContents alloc] initWithView:mapView tilesource:mapSrc centerLatLon:mapSrc.centerOfCoverage zoomLevel:17 maxZoomLevel:18 minZoomLevel:15 backgroundImage:image screenScale:10 ];
This will enable your zooming acording to your set parameter
In my app, I use an MKPolyline to track the user's path. Sometimes (and not all the time, which I don't understand), when a new line segment gets added to the map, the entire line flashes. Sometimes it doesn't. This is the code being used to add the lines:
CLLocationCoordinate2D coords[2];
coords[0] = CLLocationCoordinate2DMake(newLocation.coordinate.latitude, newLocation.coordinate.longitude);
coords[1] = CLLocationCoordinate2DMake(oldLocation.coordinate.latitude, oldLocation.coordinate.longitude);
MKPolyline* line = [MKPolyline polylineWithCoordinates:coords count:2];
[mapView addOverlay:line];
Am I missing something?
Edit: This usually happens upon the app's return from being sent to the background. I'm not exactly sure why, though, because I am only adding an overlay, not modifying the entire mapView.overlays array. ...right?
This may not be related, but Apple does state in the Managing the Map's Overlay Objects section of the Location Awareness Programming Guide...
Because the map view is an interface item, any modifications to the
overlays array should be synchronized and performed on the
application’s main thread.
I think your best bet is to try to get the flash over with before you show the map to the user.
Try one of the following:
[mapView setNeedsDisplay];
or
if ([[mapView overlays] count] > 0){
[[[mapView overlays] lastObject] setNeedsDisplay];
}
Put these in either your "viewWillAppear" method, or the "applicationWillEnterForeground" method in AppDelegate.m.