How to make a MKMap fit inside the specified View-Region? - ios

i've got a little Problem on setting up a MKMapView.
I really just want that the complete map fits into the MkMapView-Region specified inside
the Storyboard.
But it seems that it is not possible to zoom or scale the map, with the result that the whole world is visible.
Here is what it looks like:
So if i want to show the connected annotations at the same time, it wont work if they are to far away from each other. Cause it is not possible to make the whole map fit.
Maybe i am missing a step on setting the MapView up but i dont get it.
Any Ideas what i am doing wrong ?

You can use the following method of MKMapView
- (void)setRegion:(MKCoordinateRegion)region animated:(BOOL)animated
to set center point and zoom level.

Hope this will help you.
If there is only 1 annotation, then lets have a good zoom say 10x. Else zoom till we just see all the annotations ( + some extra padding :)
if ([currentMapView.annotations count] == 1) {
region.span.latitudeDelta = 0.02;
region.span.longitudeDelta = 0.02;
} else {
region.span.latitudeDelta = fabs(topLeftCoord.latitude - bottomRightCoord.latitude) * 1.1; // Add a little extra space on the sides
region.span.longitudeDelta = fabs(bottomRightCoord.longitude - topLeftCoord.longitude) * 1.1; // Add a little extra space on the sides
}

Related

MKMapView Region

I have a question regarding setting the region on my MKMapView.
I need to set the mapview to display a specific region when my view first loads.
The north east and south west latitude and longitude of this region is:
North East Coordinate Lat:59.623724 Long:2.911587
South West Coordinate Lat:49.004833 Long:-11.361825
Further to this, I would like to 'lock' the mapview to this region. Ideally the lock will be transparent, i.e: the coordinates above represent the maximum extent of the MKMapView. However if it is simply a case of checking the northeast and southwest coordinates within
- (void)mapView:(MKMapView *)aMapView regionDidChangeAnimated:(BOOL)animated
and resetting the view if they exceed my maximum range, that would be acceptable to me also.
Many thanks for any pointers on this matter.
EDIT:
Regarding the first part of my question, I have figured out I can set the initial region on the MKMapView using the following code:
CLLocationCoordinate2D neCoord;
neCoord.latitude = 59.787643;
neCoord.longitude = 3.025857;
CLLocationCoordinate2D swCoord;
swCoord.latitude = 49.394171;
swCoord.longitude = -11.036642;
MKCoordinateRegion region;
region.center.latitude = neCoord.latitude - (neCoord.latitude - swCoord.latitude) * 0.5;
region.center.longitude = neCoord.longitude + (swCoord.longitude - neCoord.longitude) * 0.5;
region.span.latitudeDelta = fabs(neCoord.latitude - swCoord.latitude); // Add a little extra space on the sides
region.span.longitudeDelta = fabs(swCoord.longitude - neCoord.longitude); // Add a little extra space on the sides
region = [self.mapView regionThatFits:region];
[self.mapView setRegion:region animated:YES];
First, you'll need to make sure you set the region on the map view after the view has been displayed. If you set it before the map has loaded, it probably won't center on that region. Once you've done that, just set self.mapView.zoomEnabled = NO; and self.mapView.scrollEnabled = NO; and it will prevent the user from moving the map around.
If you want to lock the maximum bounds the user can view but still allow scrolling and zooming, you will have to use -mapView:regionDidChangeAnimated: and 'bump' the user back inside your bounds if they leave it. Note that the user experience for this will probably suck - they'll pan around, let go, and then the map will suddenly move back to the region you defined. You could try using -mapView:regionWillChangeAnimated: and modify the map region if they left your boundaries, that could be a little less jarring.

Any Workaround to MKUserTrackingModeFollowWithHeading Bug in iOS6?

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 …

MKMapView setRegion to Small Area causes Failed Satellite Image Loading

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];
}
}

New foursquare venue detail map

I really love the way foursquare designed venue detail view. Especially the map with venue location in the "header" of view ... How was it done? Details are obviously some uiscrollview (maybe uitableview?) and behind it (in the header) there is a map so when you scroll up the map is beeing uncovered as the scroll view bounces... does anyone has an idea how to do this?
Here's the way I manage to reproduce it:-
You need a UIViewController with a UIScrollView as its view. Then, the content of the UIView you add to your scrollview should look like this :-
- The frame of the MKMapView have a negative y position. In this case, we can only see 100pts of the maps in the default state (before dragging).
- You need to disable zooming and scrolling on your MKMapView instance.
Then, the trick is to move down the centerCoordinate of the MKMapView when you drag down, and adjust its center position.
For that, we compute how much 1point represent as a delta latitude so that we know how much the center coordinate of the map should be moved when being dragged of x points on the screen :-
- (void)viewDidLoad {
[super viewDidLoad];
UIScrollView* scrollView = (UIScrollView*)self.view;
[scrollView addSubview:contentView];
scrollView.contentSize = contentView.frame.size;
scrollView.delegate = self;
center = CLLocationCoordinate2DMake(43.6010, 7.0774);
mapView.region = MKCoordinateRegionMakeWithDistance(center, 1000, 1000);
mapView.centerCoordinate = center;
//We compute how much latitude represent 1point.
//so that we know how much the center coordinate of the map should be moved
//when being dragged.
CLLocationCoordinate2D referencePosition = [mapView convertPoint:CGPointMake(0, 0) toCoordinateFromView:mapView];
CLLocationCoordinate2D referencePosition2 = [mapView convertPoint:CGPointMake(0, 100) toCoordinateFromView:mapView];
deltaLatFor1px = (referencePosition2.latitude - referencePosition.latitude)/100;
}
Once those properties are initialized, we need to implement the behavior of the UIScrollViewDelegate. When we drag, we convert the move expressed in points to a latitude. And then, we move the center of the map using the half of this value.
- (void)scrollViewDidScroll:(UIScrollView *)theScrollView {
CGFloat y = theScrollView.contentOffset.y;
// did we drag ?
if (y<0) {
//we moved y pixels down, how much latitude is that ?
double deltaLat = y*deltaLatFor1px;
//Move the center coordinate accordingly
CLLocationCoordinate2D newCenter = CLLocationCoordinate2DMake(center.latitude-deltaLat/2, center.longitude);
mapView.centerCoordinate = newCenter;
}
}
You get the same behavior as the foursquare app (but better: in the foursquare app, the maps recenter tends to jump, here, changing the center is done smoothly).
The example above is nice. If you need more help, I think they're using something very similar to RBParallaxTableViewController. https://github.com/Rheeseyb/RBParallaxTableViewController
It's essentially the same effect that Path uses for its header photo.
Yonel's answer is nice, but I found a problem as I have a pin at the center of the map. Because the negative Y, the point is hidden under my UINavigationBar.
Then, I didn't set the Negative Y, and I correct my mapView.frame according the scroll offset.
My mapView is 320 x 160
_mapView.frame = CGRectMake(0, 160, 320, -160+y);
Hope this helps someone.

Zooming out with RMMapView constrained to coordinates

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

Resources