iOS移动开发社区iOS开发iOS开发技术讨论

iOS 原生地图MKMapView上添加图片遮盖物

2016-09-07  本文已影响2039人  踢足球的程序员

未添加遮盖物效果:


WechatIMG2.png

添加遮盖物后效果:


WechatIMG3.png

MKMapView上添加图片遮盖物的原理和添加轨迹的原理基本相同(轨迹可参考上一篇文章),都需要自定义图层(实现MKOverlay协议)和渲染器(继承MKOverlayRenderer)。

CustomOverlay.h实现:

#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>

@interface CustomOverlay : NSObject<MKOverlay>

@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
@property (nonatomic, readonly) MKMapRect boundingMapRect;

- (id)initWithRect:(MKMapRect)rect;

@end

CustomOverlay.m实现:

#import "CustomOverlay.h"

@interface CustomOverlay ()

@property (nonatomic, readwrite) CLLocationCoordinate2D coordinate;
@property (nonatomic, readwrite) MKMapRect boundingMapRect;

@end

@implementation CustomOverlay

@synthesize coordinate      = _coordinate;
@synthesize boundingMapRect = _boundingMapRect;

#pragma mark - Initalize

- (id)initWithRect:(MKMapRect)rect
{
    if (self = [super init])
    {
        self.boundingMapRect = rect;
    }
    
    return self;
}

@end

CustomOverlayRenderer.h实现:

#import <MapKit/MapKit.h>

@interface CustomOverlayRenderer : MKOverlayRenderer

@end

CustomOverlayRenderer.m实现:(注意:绘制image要先转CGImageRef在绘制,网上很多方式甚至高德提供的绘制方法都会让cpu瞬间200%,真机调试用不到5分钟就烫手了。。。)

#import "CustomOverlayRenderer.h"
#import "CustomOverlay.h"

@interface CustomOverlayRenderer ()

@property (nonatomic, strong) UIImage *image;

@end

@implementation CustomOverlayRenderer

- (id) initWithOverlay:(id<MKOverlay>)overlay{
    self = [super initWithOverlay:overlay];
    if (self){
        self.image = [UIImage imageNamed:@"MapHiddenBG.png"];
    }
    return self;
}

- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context
{
    @autoreleasepool {
        CustomOverlay *overlay = (CustomOverlay *)self.overlay;
        
        if (overlay == nil)
        {
            NSLog(@"overlay is nil");
            return;
        }
        
        MKMapRect theMapRect    = [self.overlay boundingMapRect];
        CGRect theRect          = [self rectForMapRect:theMapRect];
        
        // 绘制image
        CGImageRef imageReference = self.image.CGImage;
        CGContextScaleCTM(context, 1.0, -1.0);
        CGContextTranslateCTM(context, 0.0, -theRect.size.height);
        CGContextDrawImage(context, theRect, imageReference);
    }
}
@end

类都实现了,剩下的就是正确的在地图上添加我们自定义的图层:(前面那一堆都是计算轨迹在屏幕中显示位置的,也是根我项目相关,可不用理睬)

//设置地图在可见范围
    MKMapRect mapRect = MKMapRectNull;
    for ( NSDictionary *dic in self.runningData.locationArray) {
        CLLocationDegrees latitude  = [dic[@"latitude"] doubleValue];
        CLLocationDegrees longitude = [dic[@"longitude"] doubleValue];
        CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(latitude, longitude);
        
        MKMapPoint annotationPoint = MKMapPointForCoordinate(coordinate);
        MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0, 0);
        if (MKMapRectIsNull(mapRect)) {
            mapRect = pointRect;
        } else {
            mapRect = MKMapRectUnion(mapRect, pointRect);
        }
    }
    
    const CGFloat screenEdgeInset = kScreenEdgeInset;
    UIEdgeInsets mapInset = UIEdgeInsetsMake(screenEdgeInset, screenEdgeInset, screenEdgeInset*8, screenEdgeInset);
    mapRect = [self.mapView mapRectThatFits:mapRect edgePadding:mapInset];
    [self.mapView setVisibleMapRect:mapRect edgePadding:mapInset animated:NO];
    
    //添加图片遮盖层
    self.mapHiddenImageOverlay = [[CustomOverlay alloc] initWithRect:self.mapView.visibleMapRect];
    [self.mapView addOverlay:self.mapHiddenImageOverlay level:1];

添加上了,便会调用rendererForOverlay这个代理方法:(viewForOverlay别实现这个了,这个方法已经标注ios7以后会随时销毁,再信苹果一次,即便很多标注销毁的方法到今天为止也没有几个真正销毁的)

#pragma mark -
#pragma mark - MKMapView Delegate
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id <MKOverlay>)overlay{
    if([overlay isKindOfClass:[CustomOverlay class]]){
        //遮挡地图图片
        CustomOverlayRenderer *renderer = [[CustomOverlayRenderer alloc] initWithOverlay:overlay];
        return renderer;
    }
    return nil;
}

到此,地图上图片遮盖物的功能已经实现了,但美中不足的是CustomOverlayRenderer中drawMapRect是按顺序加载瓦砾,也就是一块一块绘制,性能不好的手机上瓦砾的加载效果还是很明显的,暂时还没找到一次性绘制整张图片的方法,求指点~

上一篇下一篇

猜你喜欢

热点阅读