写在前面:
项目需求用到这个功能,主要目的是实现老师设置位置签到范围,学生在一定范围内进行签到的功能。
功能如下方截图:
屏幕快照 2019-01-28 上午10.29.26.png
简要介绍:
下面记录一下主要的实现流程,功能的实现主要是根据百度地图开发者官网提供的api文档,各项功能之间组合。百度地图的sdk现在分成了地图功能和定位功能两块不同的sdk,baidumapapi这个是基础的地图功能,bmklocationkit这个是定位功能。项目里实现定位签到功能用的的sdk包括上面说的这两个模块,所以在用cocopods引入framework的时候,需要引入: #百度地图 pod 'bmklocationkit' pod 'baidumapkit'
功能实现
一、在appdelegate.m文件中引入:
1
2
|
#import <baidumapapi_base/bmkbasecomponent.h> #import <bmklocationkit/bmklocationcomponent.h> |
加入功能代码:
1
2
3
4
5
6
7
8
9
10
11
|
#pragma mark 百度地图设置 - ( void )configbaidumap { nsstring *ak = @ "xxxx" ; bmkmapmanager *mapmanager = [[bmkmapmanager alloc] init]; self.mapmanager = mapmanager; bool ret = [mapmanager start:ak generaldelegate:nil]; [[bmklocationauth sharedinstance] checkpermisionwithkey:ak authdelegate:self]; if (!ret) { nslog(@ "manager start failed!" ); } } |
二、在用到地图定位功能的viewcontroller中
1
2
3
|
#import <bmklocationkit/bmklocationcomponent.h> #import <baidumapapi_base/bmkbasecomponent.h>//引入base相关所有的头文件 #import <baidumapapi_map/bmkmapcomponent.h>//引入地图功能所有的头文件 |
遵循协议<bmkmapviewdelegate,bmklocationmanagerdelegate>
声明全局变量
1
2
3
4
5
6
|
@property (nonatomic, strong) bmkuserlocation *userlocation; //当前位置对象 @property (nonatomic, strong) bmklocationmanager *locationmanager; /** locationmanager*/ @property (nonatomic, strong) bmkmapview *mapview; /** 百度地图*/ //@property (nonatomic, strong) bmkpointannotation* annotation ;/** 标记*/ @property (nonatomic, strong) nsmutablearray *annotationarr; /** 标记数组*/ @property (nonatomic, strong) nsmutablearray *circlearr; /** 圆形数组*/ |
地图sdk文档中建议在以下代码中如此设置, 目的是控制内存
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
- ( void )viewwillappear:( bool )animated { [super viewwillappear:animated]; [_mapview viewwillappear]; _mapview.delegate = self; } - ( void )viewwilldisappear:( bool )animated { [super viewwilldisappear:animated]; [_mapview viewwilldisappear]; _mapview.delegate = nil; } - ( void )dealloc { if (_mapview) { _mapview = nil; } } |
初始化数组,这两个数组在接下来会用到
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
- (nsmutablearray *)annotationarr { if (!_annotationarr) { _annotationarr = [nsmutablearray array]; } return _annotationarr; } - (nsmutablearray *)circlearr { if (!_circlearr) { _circlearr = [nsmutablearray array]; } return _circlearr; } |
添加地图view
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
#pragma mark 添加地图 - ( void )addsignmapbgview { if (!self.mapbgview) { uiview *mapbgview = [uiview new ]; self.mapbgview = mapbgview; mapbgview.backgroundcolor = [commutls colorwithhexstring:app_bgcolor]; [self addsubview:mapbgview]; [mapbgview makeconstraints:^(masconstraintmaker *make) { make.top.equalto(self.tipview.bottom); make.left.right.bottom.equalto(0); }]; _mapview = [[bmkmapview alloc] initwithframe:cgrectzero]; // _mapview.delegate = self; [_mapview setzoomlevel:21]; //精确到5米 _mapview.showsuserlocation = yes; //显示定位图层 [mapbgview addsubview:_mapview]; [_mapview makeconstraints:^(masconstraintmaker *make) { make.edges.equalto(0); }]; _mapview.usertrackingmode = bmkusertrackingmodenone; } } |
初始化地图定位:这里我用的是一次定位而没有选择持续定位。
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
|
#pragma mark 初始化locationmanager - ( void )inituserlocationmanager { //因为mapview是在一个分离出来的view中创建的,所以在这里将signsettypeview中的mapview赋给当前viewcontroller的mapview; self.mapview = self.mainview.signsettypeview.mapview; self.mapview.delegate = self; // self.annotation = [[bmkpointannotation alloc] init]; // self.mapview是bmkmapview对象 //精度圈设置 bmklocationviewdisplayparam *param = [[bmklocationviewdisplayparam alloc] init]; //设置显示精度圈,默认yes param.isaccuracycircleshow = yes; //精度圈 边框颜色 param.accuracycirclestrokecolor = [uicolor colorwithred:242/255.0 green:129/255.0 blue:126/255.0 alpha:1]; //精度圈 填充颜色 param.accuracycirclefillcolor = [uicolor colorwithred:242/255.0 green:129/255.0 blue:126/255.0 alpha:0.3]; [self.mapview updatelocationviewwithparam:param]; self.userlocation = [[bmkuserlocation alloc] init]; //初始化实例 _locationmanager = [[bmklocationmanager alloc] init]; //设置delegate _locationmanager.delegate = self; //设置返回位置的坐标系类型 _locationmanager.coordinatetype = bmklocationcoordinatetypebmk09ll; //设置距离过滤参数 _locationmanager.distancefilter = kcldistancefilternone; //设置预期精度参数 _locationmanager.desiredaccuracy = kcllocationaccuracybest; //设置应用位置类型 _locationmanager.activitytype = clactivitytypeautomotivenavigation; //设置是否自动停止位置更新 _locationmanager.pauseslocationupdatesautomatically = no; //设置是否允许后台定位 //_locationmanager.allowsbackgroundlocationupdates = yes; //设置位置获取超时时间 _locationmanager.locationtimeout = 15; //设置获取地址信息超时时间 _locationmanager.regeocodetimeout = 15; //请求一次定位 [self requestlocation]; } |
请求定位,获取经纬度
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
|
#pragma mark 请求定位 - ( void )requestlocation { [_locationmanager requestlocationwithregeocode:yes withnetworkstate:yes completionblock:^(bmklocation * _nullable location, bmklocationnetworkstate state, nserror * _nullable error) { if (error) { nslog(@ "locerror:{%ld - %@};" , ( long )error.code, error.localizeddescription); } if (location) { //得到定位信息,添加annotation if (location.location) { nslog(@ "loc = %@" ,location.location); } if (location.rgcdata) { nslog(@ "rgc = %@" ,[location.rgcdata description]); } if (!location) { return ; } if (!self.userlocation) { self.userlocation = [[bmkuserlocation alloc] init]; } self.userlocation.location = location.location; [self.mapview updatelocationdata:self.userlocation]; cllocationcoordinate2d mycoordinate = location.location.coordinate; self.mapview.centercoordinate = mycoordinate; //赋予初始值 self.viewmodel.lat = [nsstring stringwithformat:@ "%f" , location.location.coordinate.latitude]; self.viewmodel.lng = [nsstring stringwithformat:@ "%f" ,location.location.coordinate.longitude]; self.viewmodel.radius = @ "50" ; //打印经纬度 nslog(@ "didupdateuserlocation lat %f,long %f" ,location.location.coordinate.latitude,location.location.coordinate.longitude); } nslog(@ "netstate = %d" ,state); }]; } |
地图长按选点功能实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
//长按地图选点 - ( void )mapview:(bmkmapview *)mapview onlongclick:(cllocationcoordinate2d)coordinate { if (self.annotationarr.count > 0) { [mapview removeannotations:self.annotationarr]; [self.annotationarr removeallobjects]; bmkpointannotation *annotation = [[bmkpointannotation alloc]init]; annotation.coordinate = coordinate; [self.annotationarr addobject:annotation]; [mapview addannotations:self.annotationarr]; } else { bmkpointannotation *annotation = [[bmkpointannotation alloc]init]; annotation.coordinate = coordinate; [self.annotationarr addobject:annotation]; [mapview addannotations:self.annotationarr]; } //弹出半径选择框 [self showlocationselectradiusviewwithcoordinate:coordinate]; } |
选点后弹出选择定位范围弹框
1
2
3
4
5
6
7
8
9
10
11
12
|
#pragma mark 弹出位置弹框 - ( void )showlocationselectradiusviewwithcoordinate:(cllocationcoordinate2d)coordinate { extraactlocationsignpopview *popview = [extraactlocationsignpopview new ]; [popview show]; @weakify(self); [popview.locatioonsuresignal subscribenext:^(nsstring *x) { @strongify(self); self.viewmodel.radius = x; cgfloat radius = [x floatvalue]; [self circlewithcenterwithcoordinate2d:coordinate radius:radius]; }]; } |
设置好定位点以及半径范围后绘制范围圈,开始的时候声明的circlearr在这里用来盛放添加的区域圆形,在添加新的圆圈的时候,将之前旧的移除,保证每次绘制的范围都是最新的,同理annotationarr也是这个功能,因为api有提供的- (void)addoverlays:(nsarray *)overlays;这个方法:/** *向地图窗口添加一组overlay,需要实现bmkmapviewdelegate的-mapview:viewforoverlay:函数来生成标注对应的view overlays 要添加的overlay数组 */
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
|
#pragma mark 添加区域圆形覆盖 - ( void )circlewithcenterwithcoordinate2d:(cllocationcoordinate2d )coor radius:(cgfloat)radius { nslog(@ "coordinate lat %f,long %f" ,coor.latitude,coor.longitude); //赋予点击选点值 self.viewmodel.lat = [nsstring stringwithformat:@ "%f" , coor.latitude]; self.viewmodel.lng = [nsstring stringwithformat:@ "%f" ,coor.longitude]; if (self.circlearr.count > 0) { [_mapview removeoverlays:self.circlearr]; [self.circlearr removeallobjects]; bmkcircle *circle = [bmkcircle circlewithcentercoordinate:coor radius:radius]; [self.circlearr addobject:circle]; [_mapview addoverlays:self.circlearr]; } else { bmkcircle *circle = [bmkcircle circlewithcentercoordinate:coor radius:radius]; [self.circlearr addobject:circle]; [_mapview addoverlays:self.circlearr]; } } #pragma mark 重绘overlay - (bmkoverlayview *)mapview:(bmkmapview *)mapview viewforoverlay:(id <bmkoverlay>)overlay{ if ([overlay iskindofclass:[bmkcircle class ]]){ bmkcircleview* circleview = [[bmkcircleview alloc] initwithoverlay:overlay]; circleview.fillcolor = [uicolor colorwithred:33/255.0 green:196/255.0 blue:206/255.0 alpha:0.3]; circleview.strokecolor = [uicolor colorwithred:33/255.0 green:196/255.0 blue:206/255.0 alpha:1]; circleview.linewidth = 1.0; return circleview; } return nil; } |
至此,在地图上选点进行签到功能基本实现,另外,关于 自定义的范围圆圈的颜色,边框大小都是可以自定义的,选点的标记也是可以自定义的,官方文档有说明
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。
原文链接:https://www.jianshu.com/p/e948a3bfe600