高德地图sdk是目前国内使用比较多的地图类sdk(还有百度地图也不错),目前项目中也用到了,但是相关封装还是不够清晰。为了做好这一层封装,首先需要把高德地图sdk研究一下。
高德地图有各种语言版本的sdk,其中iOS的sdk就包含基本sdk、云图sdk,导航sdk。后两个sdk暂时用不到,而基本sdk中又包含2d(栅格地图)和3d(矢量地图)两个版本的库以及搜索的库。今天要分析的就是2d和搜索的framework,最新的sdk版本是2.4.0。
高德地图sdk是目前国内使用比较多的地图类sdk(还有百度地图也不错),目前项目中也用到了,但是相关封装还是不够清晰。为了做好这一层封装,首先需要把高德地图sdk研究一下。
高德地图有各种语言版本的sdk,其中iOS的sdk就包含基本sdk、云图sdk,导航sdk。后两个sdk暂时用不到,而基本sdk中又包含2d(栅格地图)和3d(矢量地图)两个版本的库以及搜索的库。今天要分析的就是2d和搜索的framework,最新的sdk版本是2.4.0。
几个核心类说明
######MAMapView
地图视图类,sdk中最重要的一个类,用来负责地图的展示,该类直接从UIView继承而来。
1、属性visibleMapRect1
self.mapView.visibleMapRect = MAMapRectMake(220880104, 101476980, 272496, 466656);
它定义了地图的可见范围,如下图所示:
我们如果改变visibleMapRect的大小,地图就会显示不同的区域。
2、属性mapType
地图类型,有两种类型: 普通地图和卫星地图,我们经常用到的就是普通地图1
2
3
4
5typedef NS_ENUM(NSInteger, MAMapType)
{
MAMapTypeStandard, // 普通地图
MAMapTypeSatellite // 卫星地图
};
3、属性showTraffic
是否展示路况拥堵信息,默认是不展示的,一般也用不到。
4、属性scrollEnabled和zoomEnabled
MAMapView虽然不是UIScrollView,但自身也实现了滚动和缩放功能(UIWebView同理)。这两个属性可以控制缩放和滚动的开关,默认都是打开的。
5、属性logoCenter和logoSize
高德的logo位置和大小,这个logo是需要显示出来的,不能隐藏不能遮挡(尊重知识产权)
6、属性showsCompass、compassOrigin、compassSize
地图的罗盘是否展示,展示的位置和大小
7、属性showsScale、scaleOrigin、scaleSize
地图的比例尺是否展示,展示的位置和大小
8、属性centerCoordinate
地图中心点的经纬度,改变它不会影响缩放比例。
9、属性showsUserLocation、userLocation、userTrackingMode
是否显示用户位置,用户位置的数据、用户追踪的模式。
10、属性annotations
地图上的标注,显示对应位置有什么东西,比较常用。
11、属性overlays
地图上的覆盖图形,能够在地图指定位置绘制自定义的图层,比较常用。
12、属性distanceFilter、desiredAccuracy、headingFilter
最小更新距离,定位精度,最小更新角度。
13、协议,MAMapViewDelegate,作为一个自定义的视图,当其数据对应数据发生变化时,肯定会有一些函数回调来改变自身。这些方法都被集中在MAMapViewDelegate中。一共有18个方法,大致可以分为4类:地图区域改变、用户位置发生变化、标注的创建和事件响应已经覆盖层的一些逻辑。个人觉得这个协议太大了,不符合接口分离原则 。
######AMapSearchAPI
AMapSearchAPI是一个NSObject,代表高德地图的搜索功能。
1、属性timeOut。
搜索请求超时时间,默认是20秒。
2、查询接口,不同的查询类型有不同的查询接口。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20//POI查询接口函数,即根据 POI 参数选项进行 POI 查询。
- (void)AMapPlaceSearch:(AMapPlaceSearchRequest *)request;
//路径规划查询接口。
- (void)AMapNavigationSearch:(AMapNavigationSearchRequest *)request;
//输入提示查询接口。
- (void)AMapInputTipsSearch:(AMapInputTipsSearchRequest *)request;
//地址编码查询接口。
- (void)AMapGeocodeSearch:(AMapGeocodeSearchRequest *)request;
//逆地址编码查询接口。
- (void)AMapReGoecodeSearch:(AMapReGeocodeSearchRequest *)request;
//公交线路查询接口。
- (void)AMapBusLineSearch:(AMapBusLineSearchRequest *)request;
//公交车站查询接口。
- (void)AMapBusStopSearch:(AMapBusStopSearchRequest *)request;
3、协议AMapSearchDelegate,包含对各种请求接口成功失败的回调。
可以实现的功能
######自定义用户坐标点
如果起用了定位,如下的方法会被调用到,因为自身打点也是一个Annotation,但这个Annotation的类型是MAUserLocation。然后通过设置MAUserLocationRepresentation,就可以将用户坐标点进行自定义。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19- (void)mapView:(MAMapView *)mapView didAddAnnotationViews:(NSArray *)views
{
MAAnnotationView *view = views[0];
// 放到该方法中用以保证userlocation的annotationView已经添加到地图上了。
if ([view.annotation isKindOfClass:[MAUserLocation class]])
{
MAUserLocationRepresentation *pre = [[MAUserLocationRepresentation alloc] init];
pre.fillColor = [UIColor colorWithRed:0.9 green:0.1 blue:0.1 alpha:0.3];
pre.strokeColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.9 alpha:1.0];
pre.image = [UIImage imageNamed:@"location.png"];
pre.lineWidth = 3;
pre.lineDashPattern = @[@6, @3];
[self.mapView updateUserLocationRepresentation:pre];
view.calloutOffset = CGPointMake(0, 0);
}
}
######用户手势
缩放和滚动有属性直接控制,单击双击也能够支持,但是为了和AnnotationView进行区分,需要用下面的方法进行过滤。1
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
######添加浮层
浮层对象是遵循MAOverlay协议的对象,可以是圆、折线和多边形。在高德sdk中,MACircle、MAPolyline、MAPolygon都是浮层对象。
然后通过1
- (void)addOverlays:(NSArray *)overlays;
将浮层对象添加到MapView中。
######自定义浮层
可以自定义浮层对象,只要符合MAOverlay协议即可。然后在绘制图层的代理方法中1
- (MAOverlayRenderer *)mapView:(MAMapView *)mapView viewForOverlay:(id <MAOverlay>)overlay
子类话一个MAOverlayRenderer并返回,该子类只要重写方法1
- (void)drawMapRect:(MAMapRect)mapRect zoomScale:(MAZoomScale)zoomScale inContext:(CGContextRef)context
该方法就如果UIView的drawRect,可以随心所欲的在上面画任何东西。
Overlay可以直接贴图,使用MAGroundOverlay类。虽然这个功能用自定义Overlay的方式也能实现,但比较麻烦。用MAGroundOverlay就很简单。
Overlay还支持大地曲线:MAGeodesicPolyline,图片tiles:MATileOverlay。
######打点标记
Annotaion就是在地图上标记一个位置,然后展示出来。展示的视图就是用MAAnnotationView。
像MapView插入Annotation的方法是:1
- (void)addAnnotation:(id <MAAnnotation>)annotation;
类似UITableView,MAAnnotationView的创建实在代理方法中实现的。1
- (MAAnnotationView *)mapView:(MAMapView *)mapView viewForAnnotation:(id<MAAnnotation>)annotation
MAAnnotationView可以自定义,可以有更好的显示效果;Annotation还支持动画,让显示的点动起来。
###搜索接口
######POI搜索
POI(Point of Interest),信息点,一家餐馆就是一个信息点。POI搜索可以根据ID、关键字、中心点搜索周边、指定范围搜索等搜索方式来满足不同的需求。代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67/* 根据ID来搜索POI. */
- (void)searchPoiByID
{
AMapPlaceSearchRequest *request = [[AMapPlaceSearchRequest alloc] init];
// B000A80WBJ hotel
// B00141IEZK dining
// B000A876EH cinema
// B000A7O1CU scenic
request.searchType = AMapSearchType_PlaceID;
request.uid = @"B000A07060";
request.requireExtension = YES;
[self.search AMapPlaceSearch:request];
}
/* 根据关键字来搜索POI. */
- (void)searchPoiByKeyword
{
AMapPlaceSearchRequest *request = [[AMapPlaceSearchRequest alloc] init];
request.searchType = AMapSearchType_PlaceKeyword;
request.keywords = @"肯德基";
request.city = @[@"010"];
request.requireExtension = YES;
[self.search AMapPlaceSearch:request];
}
/* 根据中心点坐标来搜周边的POI. */
- (void)searchPoiByCenterCoordinate
{
AMapPlaceSearchRequest *request = [[AMapPlaceSearchRequest alloc] init];
request.searchType = AMapSearchType_PlaceAround;
request.location = [AMapGeoPoint locationWithLatitude:39.990459 longitude:116.481476];
request.keywords = @"餐饮";
/* 按照距离排序. */
request.sortrule = 1;
request.requireExtension = YES;
/* 添加搜索结果过滤 */
AMapPlaceSearchFilter *filter = [[AMapPlaceSearchFilter alloc] init];
filter.costFilter = @[@"100", @"200"];
filter.requireFilter = AMapRequireGroupbuy;
request.searchFilter = filter;
[self.search AMapPlaceSearch:request];
}
/* 在指定的范围内搜索POI. */
- (void)searchPoiByPolygon
{
NSArray *points = [NSArray arrayWithObjects:
[AMapGeoPoint locationWithLatitude:39.990459 longitude:116.481476],
[AMapGeoPoint locationWithLatitude:39.890459 longitude:116.581476],
nil];
AMapGeoPolygon *polygon = [AMapGeoPolygon polygonWithPoints:points];
AMapPlaceSearchRequest *request = [[AMapPlaceSearchRequest alloc] init];
request.searchType = AMapSearchType_PlacePolygon;
request.polygon = polygon;
request.keywords = @"Apple";
request.requireExtension = YES;
[self.search AMapPlaceSearch:request];
}
######地理编码
输入提示查询1
2
3AMapInputTipsSearchRequest *tips = [[AMapInputTipsSearchRequest alloc] init];
tips.keywords = @"关键字";
[self.search AMapInputTipsSearch:tips];
输入提示回调1
2
3
4
5
6- (void)onInputTipsSearchDone:(AMapInputTipsSearchRequest *)request response:(AMapInputTipsSearchResponse *)response
{
[self.tips setArray:response.tips];
[self.displayController.searchResultsTableView reloadData];
}
搜索地理编码1
2
3
4
5
6
7
8
9AMapGeocodeSearchRequest *geo = [[AMapGeocodeSearchRequest alloc] init];
geo.address = key;
if (adcode.length > 0)
{
geo.city = @[adcode];
}
[self.search AMapGeocodeSearch:geo];
地理编码回调,得到一个地点的经纬度信息1
2
3- (void)onGeocodeSearchDone:(AMapGeocodeSearchRequest *)request response:(AMapGeocodeSearchResponse *)response
{
}
######逆地理编码
逆地理编码与地理编码正好相反,是通过经纬度来查询文字描述的位置信息。
发起逆地理编码查询1
2
3
4
5
6AMapReGeocodeSearchRequest *regeo = [[AMapReGeocodeSearchRequest alloc] init];
regeo.location = [AMapGeoPoint locationWithLatitude:coordinate.latitude longitude:coordinate.longitude];
regeo.requireExtension = YES;
[self.search AMapReGoecodeSearch:regeo];
逆地理编码回调1
2
3
4
5
6
7
8
9
10
11- (void)onReGeocodeSearchDone:(AMapReGeocodeSearchRequest *)request response:(AMapReGeocodeSearchResponse *)response
{
if (response.regeocode != nil)
{
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(request.location.latitude, request.location.longitude);
ReGeocodeAnnotation *reGeocodeAnnotation = [[ReGeocodeAnnotation alloc] initWithCoordinate:coordinate
reGeocode:response.regeocode];
[self.mapView addAnnotation:reGeocodeAnnotation];
}
}
除了以上的搜索,还有导航、搜索公交路线、公交站,这些再一般的应用中不会用到,就不介绍了。