An offscreen MKMapView behaves differently in 3.2, 4.0
- by Duane Fields
In 3.1 I've been using an "offscreen" MKMapView to create map images that I can rotate, crop and so forth before presenting them the user. In 3.2 and 4.0 this technique no longer works quite right. Here's some code that illustrates the problem, followed by my theory.
// create map view
_mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 0, MAP_FRAME_SIZE, MAP_FRAME_SIZE)];
_mapView.zoomEnabled = NO;
_mapView.scrollEnabled = NO;
_mapView.delegate = self;
_mapView.mapType = MKMapTypeSatellite;
// zoom in to something enough to fill the screen
MKCoordinateRegion region;
CLLocationCoordinate2D center = {30.267222, -97.763889};
region.center = center;
MKCoordinateSpan span = {0.1, 0.1 };
region.span = span;
_mapView.region = region;
// set scrollview content size to full the imageView
_scrollView.contentSize = _imageView.frame.size;
// force it to load
#ifndef __IPHONE_3_2
// in 3.1 we can render to an offscreen context to force a load
UIGraphicsBeginImageContext(_mapView.frame.size);
[_mapView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIGraphicsEndImageContext();
#else
// in 3.2 and above, the renderInContext trick doesn't work...
// this at least causes the map to render, but it's clipped to what appears to be
// the viewPort size, plus some padding
[self.view addSubview:_mapView];
#endif
when the map is done loading, I snap picture of it and stuff it in my scrollview
- (void)mapViewDidFinishLoadingMap:(MKMapView *)mapView {
NSLog(@"[MapBuilder] mapViewDidFinishLoadingMap");
// render the map to a UIImage
UIGraphicsBeginImageContext(mapView.bounds.size);
// the first sub layer is just the map, the second is the google layer, this sublayer structure might change of course
[[[mapView.layer sublayers] objectAtIndex:0] renderInContext:UIGraphicsGetCurrentContext()];
// we are done with the mapView at this point, we need its ram!
_mapView.delegate = nil;
[_mapView release];
[_mapView removeFromSuperview];
_mapView = nil;
UIImage* mapImage = [UIGraphicsGetImageFromCurrentImageContext() retain];
UIGraphicsEndImageContext();
_imageView.image = mapImage;
[mapImage release], mapImage = nil;
}
The first problem is that in 3.1 rendering to a context would trigger the map to begin loading. This no longer works in 3.2, 4.0. The only thing I have found would trigger the load is to temporarily add the map to the view (i.e. make it visible). The problem being that the map only renders to the visible area of the screen, plus a little padding. The frame/bounds are fine, but it appears to be "helpfully" optimizes the loading to limit the tiles to those visible on the screen or close to it.
Any ideas how to force the map to load at full size? Anyone else have this issue?