iOS开发--MKMapView截图

    地图控件MKMapView由于要从网络上加载地图数据并在内存中缓存,因此通常占用的内存开销特别大,特别是当用户进行放大缩小、快速拖动、3d旋转时,内存基本呈直线上升,单个地图控件占用百兆内存不成问题。

    假设在一个UITableView中,每个Cell的宽度和高度分别为320、150,每个Cell中都放置一个高度为320*150的MkMapView,采用Cell重用的方式,这种情况下iPhone 4s上UITableView中将最多包含4个MkMapView。又假设这里的MkMapView仅仅用于展示,不接受用户操作,此时我们保守估计每个 MkMapView占用10M内存。基于上述两种假设,不难算出,此时地图控件占用的总内存大小为40M = 4 * 10M。40M的内存对于移动应用开发,可以算是巨大的开销了。

    针对这种情况,我们提出截图的方案来有效解决这个问题。举个例子,假设UITableView显示的内容如下:

第一行:北京市地图

第二行:上海市地图

第三行:广州市地图

第四行:深圳市地图

。。。。。。。。。

第N行:某某市的地图

   解决方法就是:每一行的地图在头一次加载时,当地图数据加载完成后,将该地图截图保存为图片,等列表再次滚动到该行,我们用对应的图片来替代之前的地图。下面我们来说一下详细的实现步骤。


一、截图时机

   通常我们在使用MKMapView地图控件时,如常用的运动的APP,会在地图上添加一些大头针(MKAnnotation)和绘制一些线条(MKOverlay)。如果你的地图控件添加了大头针以及绘制了线条,那么正确的截图时机应该满足如下三个要求:1、地图数据加载完成;2、大头针绘制完成;3、线条绘制完成。

   经过分析,地图数据加载、大头针绘制以及线条绘制都是异步过程, 那么问题来了,如何判断上述三种操作已完成?没错,MkMapViewDelegate提供了相应的方法,分别对应的方法为:

地图数据加载完成:

  • mapViewDidFinishRenderingMap:fullyRendered:

大头针绘制完成:

  • mapView:didAddAnnotationViews:

线条绘制完成:

  • mapView:didAddOverlayRenderers:


二、地图截图

    地图控件继承于UIView,截图的方法这里就不细讲了,直接上代码:

+ (UIImage *) imageWithUIView:(UIView *)view
{
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, [[UIScreen mainScreen] scale]);
    [view.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

三、保存图片

   保存图片时,注意图片的命名,保证图片能够对应上相应的MKMapView,如:北京.png,上海.png,广州.png,等等。保存图片的代码如下:

+ (BOOL)saveImage:(UIImage*)image WithName:(NSString*)imageName
{
    NSString *imageDir = [self getDir];
    NSString *imagePath = [imageDir stringByAppendingPathComponent:imageName];
    BOOL isCreated = [UIImagePNGRepresentation(image) writeToFile:imagePath options:NSAtomicWrite error:nil];
    
    return isCreated;
}

四、整体实现

- (void)doScreenshot
{
    if (_isDrawAnnotationsDone && _isRenderMapDone && _isDrawOverlayDone) {
         UIImage *mapImage = [self imageWithUIView:_mapView];
         [self saveImage:mapImage WithName:@"xx.png"];
    }
}

- (void)mapViewDidFinishRenderingMap:(MKMapView *)mapView fullyRendered:(BOOL)fullyRendered
{
    _isRenderMapDone = YES;
    [self doScreenshot];
}


- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views
{
    _isDrawAnnotationsDone = YES;
    [self doScreenshot];
}


- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view{
    _isDrawOverlayDone = YES;
   [self doScreenshot];
}


转载请标明原文出处!!!



你可能感兴趣的:(iOS)