iOS地图SDK支持自定义瓦片图层(TileOverlay), 该图层支持开发者添加自有瓦片数据。该图层可随地图的平移、缩放、旋转等操作做相应的变换,它仅位于底图之上(即瓦片图层将会遮挡底图,不遮挡其他图层),瓦片图层的添加顺序不会影响其他图层(例如:POI搜索图层、我的位置图层等)的叠加关系,适用于开发者拥有某一区域的地图,并希望使用此区域地图覆盖百度地图相应区域的情况。
通过瓦片图层可对基础底层地图添加额外的特性,如:某个商场的室内信息、某个景区的详情等等。自定义图层类是BMKTileOverlay,它定义了能添加到基础底层地图的图片集合。
添加瓦片图层的前提是使用球面墨卡托投影生成了相应的瓦片,并按照生成的格式部署在您的服务器上。
百度地图SDK根据不同的比例尺将地图划分成若干个瓦片,并且以中心点经纬度(0,0)开始计算瓦片,当地图显示缩放级别增大时,每一个瓦片被划分成4 个瓦片。
如: 地图级别为0时,只有1张瓦片;地图级别为1时,会分成4 张瓦片;地图级别为2时,会分成4的2次方 = 16 张瓦片。依次类推,地图级别为n时,总共划分的瓦片为:4的n次方。为了保证瓦片的显示效果,第n级的瓦片显示的地图level范围为[n - 0.5, n + 0.5)。
本地加载
将图片打包于应用内,适用于图片较小且不需要频繁变更,通过继承BMKSyncTileLayer实现。
/** @brief 通过同步方法获取瓦片数据,是一个抽象类,需要通过继承该类,并重载 tileForX:y:zoom: 方法 瓦片图片是jpeg或者png格式,size为256x256 */ @interface BMKLocalSyncTileLayer: BMKSyncTileLayer @end #pragma mark - BMKLocalSyncTileLayer @implementation BMKLocalSyncTileLayer /** @brief 通过同步方法获取瓦片数据,子类必须实现该方法 这个方法会在多个线程中调用,需要考虑线程安全 @param (x, y, zoom)x,y表示瓦片的行列号,zoom为地图的缩放等级 @return UIImage所对应瓦片的UIImage对象 */ - (UIImage *)tileForX:(NSInteger)x y:(NSInteger)y zoom:(NSInteger)zoom { NSString *imageName = [NSString stringWithFormat:@"%ld_%ld_%ld.jpg", zoom, x, y]; UIImage *image = [UIImage imageNamed:imageName]; return image; } @end
import UIKit class BMKLocalSyncTileLayer: BMKSyncTileLayer { /** 通过同步方法获取瓦片数据 @param x 瓦片图层x坐标 @param y 瓦片图层y坐标 @param zoom 瓦片图层的比例尺大小 @return (x,y,zoom)对应瓦片的UIImage对象 */ override func tileFor(x: Int, y: Int, zoom: Int) -> UIImage! { let imageName: String = String(format: "%ld_%ld_%ld.jpg", arguments: [zoom, x, y]) if let image: UIImage = UIImage(named: imageName) { return image } else { return nil } } }
//初始化BMKLocalSyncTileLayer的实例 BMKLocalSyncTileLayer *syncTile = [[BMKLocalSyncTileLayer alloc] init];
//初始化BMKLocalSyncTileLayer的实例 let syncTile: BMKLocalSyncTileLayer = BMKLocalSyncTileLayer()
//syncTile的最大Zoom值,默认21,且不能小于minZoom syncTile.maxZoom = 17; //syncTile的最小Zoom值,默认3 syncTile.minZoom = 16;
//syncTile的最大Zoom值,默认21,且不能小于minZoom syncTile.maxZoom = 17 //syncTile的最小Zoom值,默认3 syncTile.minZoom = 16
/** 向地图View添加Overlay,需要实现BMKMapViewDelegate的-mapView:viewForOverlay: 方法来生成标注对应的View @param overlay 要添加的overlay */ [_mapView addOverlay:syncTile];
/** 向地图View添加Overlay,需要实现BMKMapViewDelegate的-mapView:viewForOverlay: 方法来生成标注对应的View @param overlay 要添加的overlay */ mapView.add(syncTile)
#pragma mark - BMKMapViewDelegate /** 根据overlay生成对应的BMKOverlayView @param mapView 地图View @param overlay 指定的overlay @return 生成的覆盖物View */ - (BMKOverlayView *)mapView:(BMKMapView *)mapView viewForOverlay:(id <BMKOverlay>)overlay { if ([overlay isKindOfClass:[BMKTileLayer class]]) { BMKTileLayerView *view = [[BMKTileLayerView alloc] initWithTileLayer:overlay]; return view; } return nil; }
//MARK:BMKMapViewDelegate func mapView(_ mapView: BMKMapView!, viewFor overlay: BMKOverlay!) -> BMKOverlayView! { if overlay .isKind(of: BMKTileLayer.self) { let view: BMKTileLayerView = BMKTileLayerView.init(tileLayer: overlay as? BMKTileLayer) return view } return nil }
效果如下图:
在线加载
使用在线下载,将图片存放于开发者提供的服务中,提供给SDK一个URL模板,适用于图片需要随时变更,下面举例说明添加在线瓦片图层的步骤:
URL模版(URLTemplate)是一个包含"{x}","{y}","{z}"的字符串,"{x}","{y}"表示tile的坐标,"{z}"表示当tile显示的级别。"{x}","{y}","{z}"会被tile的坐标值所替换,并生成用来加载tile图片数据的URL 。例如: http://server/path?x={x}&y={y}&z={z}。
/** @brief 通过提供url模板的方法,提供数据源。不应该继承该类,且必须通过initWithURLTemplate: 方法来初始化,瓦片图片是jpeg或者png格式,size为256x256 */ BMKURLTileLayer *urlTileLayer = [[BMKURLTileLayer alloc] initWithURLTemplate:@"http://api0.map.bdimg.com/customimage/tile?&x={x}&y={y}&z={z}&udt=20150601&customid=light"];
/** @brief 通过提供url模板的方法,提供数据源。不应该继承该类,且必须通过initWithURLTemplate: 方法来初始化,瓦片图片是jpeg或者png格式,size为256x256 */ let urlTile: BMKURLTileLayer = BMKURLTileLayer.init(urlTemplate: " http://online1.map.bdimg.com/tile/?qt=vtile&x={x}&y={y}&z={z}&styles=pl&scaler=1&udt=20190528")
urlTileLayer.maxZoom = 21; urlTileLayer.minZoom = 17;
//urlTile的最大Zoom值,默认21,且不能小于minZoom urlTile.maxZoom = 21 //urlTile的最小Zoom值,默认3 urlTile.minZoom = 17
//urlTile的可渲染区域,默认世界范围 urlTileLayer.visibleMapRect = BMKMapRectMake(32994258, 35853667, 3122, 5541);
//urlTile的可渲染区域,默认世界范围 urlTile.visibleMapRect = BMKMapRectMake(32994258, 35853667, 3122, 5541)
[_mapView addOverlay:urlTileLayer];
mapView.add(urlTile)
- (BMKOverlayView *)mapView:(BMKMapView *)mapView viewForOverlay:(id <BMKOverlay>)overlay { if ([overlay isKindOfClass:[BMKTileLayer class]]) { BMKTileLayerView *view = [[BMKTileLayerView alloc] initWithTileLayer:overlay]; return view; } return nil; }
/** 根据overlay生成对应的BMKOverlayView @param mapView 地图View @param overlay 指定的overlay @return 生成的覆盖物View */ func mapView(_ mapView: BMKMapView!, viewFor overlay: BMKOverlay!) -> BMKOverlayView! { if overlay.isKind(of: BMKTileLayer.self) { let view: BMKTileLayerView = BMKTileLayerView.init(tileLayer: overlay as? BMKTileLayer) return view } return nil }
当前地图等级为17(_mapView.zoomLevel = 17;)效果如下图: