LocationManager.m 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. //
  2. // LocationManager.m
  3. // jiaPei
  4. //
  5. // Created by 张嵘 on 2018/9/20.
  6. // Copyright © 2018年 JCZ. All rights reserved.
  7. //
  8. #import "LocationManager.h"
  9. #import <CoreLocation/CoreLocation.h>
  10. static LocationManager *manger = nil;
  11. static dispatch_once_t onceToken;
  12. //复用annotationView的指定唯一标识
  13. static NSString *annotationViewIdentifier = @"com.Baidu.BMKPointAnnotation";
  14. @interface LocationManager () <BMKLocationAuthDelegate, BMKLocationManagerDelegate, BMKMapViewDelegate, BMKGeneralDelegate, BMKGeoCodeSearchDelegate, BMKRecommendStopSearchDelegate>
  15. @property (nonatomic, strong) BMKMapManager *mapManager; //主引擎类
  16. @property (nonatomic, strong) BMKLocationManager *locationManager; //定位对象
  17. @property (nonatomic, strong) BMKUserLocation *userLocation;//当前位置对象
  18. @property (nonatomic, assign) BOOL locationLock;//单次定位锁
  19. @property (nonatomic, strong) LocCompletedBlock locCompletedBlock;//定位回调
  20. @property (nonatomic, strong) BMKMapView *mapView;//地图View类
  21. @property (nonatomic, assign) CGSize mapSize;//地图大小
  22. @property (nonatomic, strong) UIImageView *locationView;
  23. @property (nonatomic, strong) UIButton *addressBtn;
  24. @property (nonatomic, copy) NSArray<id<BMKAnnotation>> *annotationArr;
  25. @property (nonatomic, strong) BMKGeoCodeSearch *searcher;//搜索对象
  26. @property (nonatomic, strong) SearchCompletedBlock searchCompletedBlock;//搜索回调
  27. @property (nonatomic, strong) ReverseCompletedBlock reverseCompletedBlock;//反地理编码回调
  28. @property (nonatomic, strong) CLLocationManager *cLLocationManager;
  29. @end
  30. @implementation LocationManager
  31. + (LocationManager *)sharedManager {
  32. dispatch_once(&onceToken, ^{
  33. manger = [[self alloc] init];
  34. });
  35. return manger;
  36. }
  37. - (instancetype)init {
  38. self = [super init];
  39. if (self) {
  40. @weakify(self)
  41. dispatch_async(dispatch_get_main_queue(), ^{
  42. @strongify(self)
  43. // 初始化定位SDK
  44. [[BMKLocationAuth sharedInstance] checkPermisionWithKey:BaiDuMapAK authDelegate:self];
  45. [BMKMapManager setAgreePrivacy:YES];
  46. //要使用百度地图,请先启动BMKMapManager
  47. self.mapManager = [[BMKMapManager alloc] init];
  48. // ‼️重要:设置用户是否同意SDK隐私协议,请务必在BMKLocationManager和BMKGeoFenceManager实例化之前调用,否则实例化失败
  49. [[BMKLocationAuth sharedInstance] setAgreePrivacy:YES];
  50. /**
  51. 百度地图SDK所有API均支持百度坐标(BD09)和国测局坐标(GCJ02),用此方法设置您使用的坐标类型.
  52. 默认是BD09(BMK_COORDTYPE_BD09LL)坐标.
  53. 如果需要使用GCJ02坐标,需要设置CoordinateType为:BMK_COORDTYPE_COMMON.
  54. */
  55. if ([BMKMapManager setCoordinateTypeUsedInBaiduMapSDK:BMK_COORDTYPE_GPS]) {
  56. NSLog(@"经纬度类型设置成功");
  57. } else {
  58. NSLog(@"经纬度类型设置失败");
  59. }
  60. //启动引擎并设置AK并设置delegate
  61. BOOL result = [self.mapManager start:BaiDuMapAK generalDelegate:self];
  62. if (!result) {
  63. NSLog(@"启动引擎失败");
  64. }
  65. self.cLLocationManager = [[CLLocationManager alloc] init];
  66. [self.cLLocationManager requestWhenInUseAuthorization];
  67. });
  68. }
  69. return self;
  70. }
  71. - (void)dealloc {
  72. _mapView.delegate = nil;
  73. }
  74. #pragma mark - Custom Way
  75. /**
  76. 根据大小创建地图
  77. @param size 大小
  78. @return 返回地图
  79. */
  80. - (BMKMapView *)getMapViewWithSize:(CGSize)size {
  81. self.mapView = nil;
  82. _mapSize = size;
  83. [self.mapView addSubview:self.locationView];
  84. return self.mapView;
  85. }
  86. /**
  87. 单次定位
  88. @param completeBlock 定位回调
  89. */
  90. - (void)updateLocationWithCompleteBlock:(LocCompletedBlock)completeBlock {
  91. @weakify(self)
  92. self.locationLock = YES;
  93. _locCompletedBlock = completeBlock;
  94. self.locationManager.distanceFilter = kCLDistanceFilterNone;
  95. [self.locationManager requestLocationWithReGeocode:YES withNetworkState:YES completionBlock:^(BMKLocation * _Nullable location, BMKLocationNetworkState state, NSError * _Nullable error) {
  96. @strongify(self)
  97. if (_locCompletedBlock) {
  98. _locCompletedBlock(location != nil, location.location, location);
  99. }
  100. if (error) [self showErrorAlertWithError:error];
  101. }];
  102. }
  103. /**
  104. 连续定位
  105. @param distanceFilter 设定定位的最小更新距离。默认为 kCLDistanceFilterNone
  106. @param completeBlock 定位回调
  107. */
  108. - (void)updateLocationWithDistanceFilter:(NSInteger)distanceFilter CompleteBlock:(LocCompletedBlock)completeBlock {
  109. [self.locationManager startUpdatingLocation];
  110. self.locationManager.distanceFilter = distanceFilter? distanceFilter : kCLDistanceFilterNone;
  111. _locCompletedBlock = completeBlock;
  112. }
  113. /**
  114. 返回地址信息搜索结果
  115. @param address 地址(必填)
  116. @param city 城市(选填)
  117. @param completeBlock 搜索回调
  118. */
  119. - (void)onGetGeoCodeWithAddress:(NSString *)address City:(NSString *)city completeBlock:(SearchCompletedBlock)completeBlock {
  120. BMKGeoCodeSearchOption *geoCodeSearchOption = [[BMKGeoCodeSearchOption alloc]init];
  121. geoCodeSearchOption.city= city;
  122. geoCodeSearchOption.address = address;
  123. [self.searcher geoCode:geoCodeSearchOption];
  124. _searchCompletedBlock = completeBlock;
  125. }
  126. /**
  127. 返回反地理编码搜索结果
  128. @param location 定位
  129. @param completeBlock 搜索回调
  130. */
  131. - (void)onGetReverseGeoCodeWithLocation:(CLLocation *)location completeBlock:(ReverseCompletedBlock)completeBlock {
  132. BMKReverseGeoCodeSearchOption *reverseGeoCodeSearchOption = [[BMKReverseGeoCodeSearchOption alloc]init];
  133. reverseGeoCodeSearchOption.location = location.coordinate;
  134. [self.searcher reverseGeoCode:reverseGeoCodeSearchOption];
  135. _reverseCompletedBlock = completeBlock;
  136. }
  137. /**
  138. 错误弹窗
  139. */
  140. - (void)showErrorAlertWithError:(NSError *)error {
  141. switch (error.code) {
  142. case BMKLocationErrorDenied: {
  143. if (!RQ_AD_MANAGER.isFirstAppLoad) {
  144. ShowMsg(@"请在iPhone的“设置”-“隐私”-“定位服务”功能中,找到“极速驾培”打开位置访问权限");
  145. // [RQ_SHARE_FUNCTION showAlertWithTitle:@"温馨提示" message:@"请在iPhone的“设置”-“隐私”-“定位服务”功能中,找到“极速驾培”打开位置访问权限" alertControllerStyle:UIAlertControllerStyleAlert cancelButtonTitle:@"确定" otherButtonTitles:nil otherButtonStyles:nil showInWindow:NO completion:nil];
  146. }
  147. }
  148. break;
  149. default:
  150. break;
  151. }
  152. [_locationManager stopUpdatingLocation];
  153. }
  154. /**
  155. 开始定位
  156. */
  157. - (void)beginLocation{
  158. [self.locationManager startUpdatingLocation];
  159. [self.locationManager startUpdatingHeading];
  160. }
  161. #pragma mark - Search Data
  162. - (void)setupDefaultDataWithCLLocationCoordinate2D:(CLLocationCoordinate2D)locationCoordinate2D {
  163. // 初始化请求参数类BMKRecommendStopSearchOption的实例
  164. BMKRecommendStopSearchOption *option = [[BMKRecommendStopSearchOption alloc] init];
  165. // 推荐上车点经纬度 (必选)
  166. option.location = locationCoordinate2D;
  167. [self searchData:option];
  168. }
  169. - (void)searchData:(BMKRecommendStopSearchOption *)option {
  170. // 初始化BMKRecommendStopSearch实例
  171. BMKRecommendStopSearch *search = [[BMKRecommendStopSearch alloc] init];
  172. // 推荐上车点检索的代理
  173. search.delegate = self;
  174. // 初始化请求参数类BMKRecommendStopSearchOption的实例
  175. BMKRecommendStopSearchOption *stopSearchOption = [[BMKRecommendStopSearchOption alloc] init];
  176. // 推荐上车点经纬度 (必选)
  177. stopSearchOption.location = option.location;
  178. /// 推荐上车点检索
  179. /// @param recommendStopOption 推荐上车点检索信息类
  180. /// @return 成功返回YES,否则返回NO
  181. // BOOL flag = [search recommendStopSearch:stopSearchOption];
  182. // if (flag) {
  183. // NSLog(@"推荐上车点检索成功");
  184. // } else {
  185. // NSLog(@"推荐上车点检索失败");
  186. // }
  187. }
  188. #pragma mark - BMKLocationAuthDelegate 定位鉴权代理
  189. /**
  190. * @brief 返回授权验证错误
  191. * @param iError 错误号 : 为0时验证通过,具体参加BMKLocationAuthErrorCode
  192. */
  193. - (void)onCheckPermissionState:(BMKLocationAuthErrorCode)iError {
  194. if (_locCompletedBlock) {
  195. _locCompletedBlock(NO, nil, nil);
  196. }
  197. switch (iError) {
  198. case BMKLocationAuthErrorUnknown:
  199. NSLog(@"未知错误");
  200. break;
  201. case BMKLocationAuthErrorSuccess:
  202. NSLog(@"鉴权成功");
  203. break;
  204. case BMKLocationAuthErrorNetworkFailed:
  205. NSLog(@"因网络鉴权失败");
  206. break;
  207. case BMKLocationAuthErrorFailed:
  208. NSLog(@"KEY非法鉴权失败");
  209. break;
  210. default:
  211. break;
  212. }
  213. }
  214. /**
  215. 联网结果回调
  216. @param iError 联网结果错误码信息,0代表联网成功
  217. */
  218. - (void)onGetNetworkState:(int)iError {
  219. if (0 == iError) {
  220. NSLog(@"联网成功");
  221. } else {
  222. NSLog(@"联网失败:%d", iError);
  223. if (_searchCompletedBlock) {
  224. _searchCompletedBlock(NO, nil, iError);
  225. }
  226. if (_reverseCompletedBlock) {
  227. _reverseCompletedBlock(NO, nil, iError);
  228. }
  229. }
  230. }
  231. #pragma mark - BMKMapViewDelegate 地图代理
  232. - (void)mapView:(BMKMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
  233. NSLog(@"地图拖动");
  234. [UIView animateWithDuration:0.30 animations:^{
  235. self.locationView.centerY -=8;
  236. } completion:^(BOOL finished) {
  237. self.locationView.centerY +=8;
  238. }];
  239. CGPoint touchPoint = self.mapView.center;
  240. CLLocationCoordinate2D touchMapCoordinate = [self.mapView convertPoint:touchPoint toCoordinateFromView:self.mapView];//这里touchMapCoordinate就是该点的经纬度了
  241. NSLog(@"touching %f,%f",touchMapCoordinate.latitude,touchMapCoordinate.longitude);
  242. [self setupDefaultDataWithCLLocationCoordinate2D:touchMapCoordinate];
  243. BMKReverseGeoCodeSearchOption *reverseGeoCodeSearchOption = [[BMKReverseGeoCodeSearchOption alloc]init];
  244. reverseGeoCodeSearchOption.location = touchMapCoordinate;
  245. [self.searcher reverseGeoCode:reverseGeoCodeSearchOption];
  246. }
  247. /// 根据anntation生成对应的View
  248. /// @param mapView 地图View
  249. /// @param annotation 指定的标注
  250. /// @return 生成的标注View
  251. - (__kindof BMKAnnotationView *)mapView:(BMKMapView *)mapView viewForAnnotation:(id<BMKAnnotation>)annotation {
  252. if ([annotation isKindOfClass:[BMKPointAnnotation class]]) {
  253. /**
  254. 根据指定标识查找一个可被复用的标注,用此方法来代替新创建一个标注,返回可被复用的标注
  255. */
  256. BMKPinAnnotationView *annotationView = (BMKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:annotationViewIdentifier];
  257. UILabel *addressLabel = [UILabel rq_labelWithText:annotation.title font:RQRegularFont_14 textColor:RQColorFromHexString(@"#498EF5")];
  258. addressLabel.numberOfLines = 0;
  259. if (!annotationView) {
  260. /**
  261. 初始化并返回一个annotationView
  262. @param annotation 关联的annotation对象
  263. @param reuseIdentifier 如果要重用view,传入一个字符串,否则设为nil,建议重用view
  264. @return 初始化成功则返回annotationView,否则返回nil
  265. */
  266. annotationView = [[BMKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:annotationViewIdentifier];
  267. //annotationView显示的图片,默认是大头针
  268. // annotationView.image = nil;
  269. /**
  270. 默认情况下annotationView的中心点位于annotation的坐标位置,可以设置centerOffset改变
  271. annotationView的位置,正的偏移使annotationView朝右下方移动,负的朝左上方,单位是像素
  272. */
  273. annotationView.centerOffset = CGPointMake(0, 0);
  274. /**
  275. 默认情况下, 弹出的气泡位于annotationView正中上方,可以设置calloutOffset改变annotationView的
  276. 位置,正的偏移使annotationView朝右下方移动,负的朝左上方,单位是像素
  277. */
  278. annotationView.calloutOffset = CGPointMake(0, 0);
  279. //是否显示3D效果,标注在地图旋转和俯视时跟随旋转、俯视,默认为NO
  280. annotationView.enabled3D = NO;
  281. //是否忽略触摸时间,默认为YES
  282. annotationView.enabled = YES;
  283. /**
  284. 开发者不要直接设置这个属性,若设置,需要在设置后调用BMKMapView的-(void)mapForceRefresh;方法
  285. 刷新地图,默认为NO,当annotationView被选中时为YES
  286. */
  287. annotationView.selected = NO;
  288. //annotationView被选中时,是否显示气泡(若显示,annotation必须设置了title),默认为YES
  289. annotationView.canShowCallout = NO;
  290. /**
  291. 显示在气泡左侧的view(使用默认气泡时,view的width最大值为32,
  292. height最大值为41,大于则使用最大值)
  293. */
  294. annotationView.leftCalloutAccessoryView = nil;
  295. /**
  296. 显示在气泡右侧的view(使用默认气泡时,view的width最大值为32,
  297. height最大值为41,大于则使用最大值)
  298. */
  299. annotationView.rightCalloutAccessoryView = nil;
  300. /**
  301. annotationView的颜色: BMKPinAnnotationColorRed,BMKPinAnnotationColorGreen,
  302. BMKPinAnnotationColorPurple
  303. */
  304. annotationView.pinColor = BMKPinAnnotationColorGreen;
  305. annotationView.displayMinLevel = 17;
  306. //设置从天而降的动画效果
  307. annotationView.animatesDrop = NO;
  308. //当设为YES并实现了setCoordinate:方法时,支持将view在地图上拖动
  309. annotationView.draggable = NO;
  310. //当前view的拖动状态
  311. //annotationView.dragState;
  312. [annotationView addSubview:addressLabel];
  313. [addressLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
  314. make.left.mas_equalTo(annotationView.mas_right).mas_offset(8);
  315. make.centerY.mas_equalTo(annotationView);
  316. make.size.mas_equalTo(CGSizeMake(RQ_SCREEN_WIDTH / 3.f, 50.f));
  317. }];
  318. } else {
  319. [annotationView removeAllSubviews];
  320. [annotationView addSubview:addressLabel];
  321. [addressLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
  322. make.left.mas_equalTo(annotationView.mas_right).mas_offset(8);
  323. make.centerY.mas_equalTo(annotationView);
  324. make.size.mas_equalTo(CGSizeMake(RQ_SCREEN_WIDTH / 3.f, 50.f));
  325. }];
  326. }
  327. return annotationView;
  328. }
  329. return nil;
  330. }
  331. #pragma mark - BMKGeoCodeSearchDelegate 搜索代理
  332. - (void)onGetGeoCodeResult:(BMKGeoCodeSearch *)searcher result:(BMKGeoCodeSearchResult *)result errorCode:(BMKSearchErrorCode)error {
  333. if (_searchCompletedBlock) {
  334. _searchCompletedBlock(result? YES : NO, result, error);
  335. }
  336. }
  337. - (void)onGetReverseGeoCodeResult:(BMKGeoCodeSearch *)searcher result:(BMKReverseGeoCodeSearchResult *)result errorCode:(BMKSearchErrorCode)error {
  338. if (result) {
  339. if (result.poiRegions.count > 0) {
  340. BMKSearchRGCRegionInfo *info = result.poiRegions.firstObject;
  341. [self.addressBtn setTitleNormal:info.regionName];
  342. } else {
  343. [self.addressBtn setTitleNormal:result.sematicDescription];
  344. }
  345. }
  346. if (_reverseCompletedBlock) {
  347. _reverseCompletedBlock(result ? YES : NO, result, error);
  348. }
  349. }
  350. #pragma mark - BMKRecommendStopSearchDelegate
  351. /// 推荐上车点检索结果回调
  352. /// @param searcher 搜索对象
  353. /// @param recommendStopResult 搜索结果
  354. /// @param errorCode 错误号,@see BMKSearchErrorCode
  355. - (void)onGetRecommendStopResult:(BMKRecommendStopSearch *)searcher result:(BMKRecommendStopSearchResult *)recommendStopResult errorCode:(BMKSearchErrorCode)errorCode {
  356. if (errorCode == BMK_SEARCH_NO_ERROR) {
  357. if (!recommendStopResult.recommendStopInfoList && recommendStopResult.recommendStopInfoList.count == 0) {
  358. return;
  359. }
  360. [_mapView removeAnnotations:self.annotationArr];
  361. self.annotationArr = [recommendStopResult.recommendStopInfoList.rac_sequence.signal map:^id _Nullable(BMKRecommendStopInfo * _Nullable info) {
  362. BMKPointAnnotation *annotation = [[BMKPointAnnotation alloc] init];
  363. annotation.title = info.name;
  364. annotation.coordinate = info.location;
  365. return annotation;
  366. }].toArray;
  367. [_mapView addAnnotations:self.annotationArr];
  368. NSMutableArray *array = [NSMutableArray arrayWithArray:recommendStopResult.recommendStopInfoList];
  369. for (int i = 0; i< array.count -1; i++) {
  370. BOOL isEnd = NO;//判断是否已排序完成
  371. for (int j = 0; j < array.count -1 -i; j++) {
  372. BMKRecommendStopInfo *infoA = array[j];
  373. CGFloat a = infoA.distance;
  374. BMKRecommendStopInfo *infoB = array[j+1];
  375. CGFloat b = infoB.distance;
  376. if (a > b ) {
  377. isEnd = YES;
  378. [array exchangeObjectAtIndex:j withObjectAtIndex:j+1];
  379. }
  380. }
  381. if (!isEnd) {
  382. break;
  383. }
  384. }
  385. if (array.count > 0) {
  386. BMKRecommendStopInfo *info = array.firstObject;
  387. BMKPointAnnotation *annotation = [[BMKPointAnnotation alloc] init];
  388. annotation.title = info.name;
  389. annotation.coordinate = info.location;
  390. [_mapView selectAnnotation:annotation animated:YES];
  391. BMKMapStatus *status = [[BMKMapStatus alloc] init];
  392. status.targetGeoPt = info.location;
  393. status.fLevel = _mapView.zoomLevel;
  394. status.fRotation = _mapView.rotation;
  395. status.fOverlooking = _mapView.overlooking;
  396. [_mapView setMapStatus:status withAnimation:YES];
  397. }
  398. BMKRecommendStopInfo *info = [recommendStopResult.recommendStopInfoList firstObject];
  399. NSString *message = [NSString stringWithFormat:@"推荐上车点名称:%@\n推荐上车点地址:%@\n推荐点poi的uid:%@\n距查找点的距离:%.2lf\n经度:%.6lf\n纬度:%.6lf", info.name, info.address, info.uid, info.distance, info.location.longitude, info.location.latitude];
  400. [jiaPeiManager QMLogStr:message];
  401. // [NSObject rq_showAlertViewWithTitle:@"推荐上车点" message:message confirmTitle:@"确定"];
  402. } else {
  403. // [_mapView removeAnnotations:self.annotationArr];
  404. }
  405. }
  406. #pragma mark - BMKLocationManagerDelegate 定位代理
  407. /**
  408. 用户拒绝开启定位服务等原因导致的定位失败会调用的方法
  409. @brief 当定位发生错误时,会调用代理的此方法。
  410. @param manager 定位 BMKLocationManager 类。
  411. @param error 返回的错误,参考 CLError 。
  412. */
  413. - (void)BMKLocationManager:(BMKLocationManager *)manager didFailWithError:(NSError *)error {
  414. if (error) [self showErrorAlertWithError:error];
  415. }
  416. /**
  417. 处理位置坐标更新
  418. @brief 连续定位回调函数
  419. @param manager 定位 BMKLocationManager 类。
  420. @param location 定位结果,参考BMKLocation。
  421. @param error 错误信息。
  422. */
  423. - (void)BMKLocationManager:(BMKLocationManager *)manager didUpdateLocation:(BMKLocation *)location orError:(NSError *)error {
  424. if (location) {
  425. self.userLocation.location = location.location;
  426. //实现该方法,否则定位图标不出现
  427. [_mapView updateLocationData:self.userLocation];
  428. //设置当前地图的中心点,改变该值时,地图的比例尺级别不会发生变化
  429. _mapView.centerCoordinate = self.userLocation.location.coordinate;
  430. if (_locCompletedBlock) {
  431. _locCompletedBlock(location != nil , location.location, location);
  432. }
  433. [_locationManager stopUpdatingLocation];
  434. [self setupDefaultDataWithCLLocationCoordinate2D:location.location.coordinate];
  435. //发起反向地理编码检索
  436. _searcher =[[BMKGeoCodeSearch alloc]init];
  437. _searcher.delegate = self;
  438. BMKReverseGeoCodeSearchOption *reverseGeoCodeSearchOption = [[BMKReverseGeoCodeSearchOption alloc]init];
  439. reverseGeoCodeSearchOption.location = location.location.coordinate;
  440. [_searcher reverseGeoCode:reverseGeoCodeSearchOption];
  441. }
  442. }
  443. #pragma mark - Lazy loading
  444. - (BMKLocationManager *)locationManager {
  445. if (!_locationManager) {
  446. // ‼️重要:设置用户是否同意SDK隐私协议,请务必在BMKLocationManager和BMKGeoFenceManager实例化之前调用,否则实例化失败
  447. [[BMKLocationAuth sharedInstance] setAgreePrivacy:YES];
  448. _locationManager = [[BMKLocationManager alloc] init];
  449. _locationManager.delegate = self;
  450. _locationManager.coordinateType = BMKLocationCoordinateTypeBMK09LL;
  451. _locationManager.desiredAccuracy = kCLLocationAccuracyBest;
  452. _locationManager.activityType = CLActivityTypeAutomotiveNavigation;
  453. _locationManager.pausesLocationUpdatesAutomatically = NO;
  454. _locationManager.allowsBackgroundLocationUpdates = NO;
  455. _locationManager.locationTimeout = 10;
  456. }
  457. return _locationManager;
  458. }
  459. - (BMKUserLocation *)userLocation {
  460. if (!_userLocation) {
  461. _userLocation = [[BMKUserLocation alloc] init];
  462. }
  463. return _userLocation;
  464. }
  465. - (BMKMapView *)mapView {
  466. if (!_mapView) {
  467. _mapView = [[BMKMapView alloc] initWithFrame:CGRectMake(0,0,_mapSize.width, _mapSize.height)];
  468. //开启定位服务
  469. [self beginLocation];
  470. //设置mapView的代理
  471. _mapView.delegate = self;
  472. //当前地图类型
  473. _mapView.mapType = BMKMapTypeStandard;
  474. //设置地图比例尺级别
  475. _mapView.zoomLevel = 19;
  476. //设置显示定位图层
  477. _mapView.showsUserLocation = YES;
  478. //设置定位模式为普通模式
  479. _mapView.userTrackingMode = BMKUserTrackingModeHeading;
  480. //设定显式比例尺
  481. // _mapView.showMapScaleBar = YES;
  482. // 关闭旋转
  483. _mapView.rotateEnabled = NO;
  484. _mapView.ChangeCenterWithDoubleTouchPointEnabled = NO;
  485. //配置定位图层个性化样式,初始化BMKLocationViewDisplayParam的实例
  486. BMKLocationViewDisplayParam *param = [[BMKLocationViewDisplayParam alloc] init];
  487. //设置定位图标(屏幕坐标)X轴偏移量为0
  488. param.locationViewOffsetX = 0;
  489. //设置定位图标(屏幕坐标)Y轴偏移量为0
  490. param.locationViewOffsetY = 0;
  491. //设置定位图层locationView在最上层(也可设置为在下层)
  492. param.locationViewHierarchy = LOCATION_VIEW_HIERARCHY_TOP;
  493. //设置显示精度圈(因“需求:可改变精度圈大小”,关闭默认精度圈)
  494. param.isAccuracyCircleShow = YES;
  495. //跟随态旋转角度是否生效
  496. param.isRotateAngleValid = YES;
  497. //更新定位图层个性化样式
  498. [_mapView updateLocationViewWithParam:param];
  499. }
  500. return _mapView;
  501. }
  502. - (BMKGeoCodeSearch *)searcher {
  503. if (!_searcher) {
  504. _searcher =[[BMKGeoCodeSearch alloc]init];
  505. _searcher.delegate = self;
  506. }
  507. return _searcher;
  508. }
  509. - (UIImageView *)locationView {
  510. if (!_locationView) {
  511. _locationView =[[UIImageView alloc]initWithImage:[UIImage imageNamed:@"定位针"]];
  512. _locationView.center = CGPointMake(self.mapView.width/2, self.mapView.height/2);
  513. [_locationView addSubview:self.addressBtn];
  514. @weakify(self)
  515. [self.addressBtn mas_makeConstraints:^(MASConstraintMaker *make) {
  516. @strongify(self)
  517. make.bottom.mas_equalTo(_locationView.top).mas_offset(- _locationView.rq_height / 2.f);
  518. make.centerX.mas_equalTo(_locationView);
  519. make.size.mas_equalTo(CGSizeMake(RQ_SCREEN_WIDTH / 3.f, 54.f));
  520. self.addressBtn.layer.cornerRadius = 27.f;
  521. }];
  522. }
  523. return _locationView;
  524. }
  525. - (UIButton *)addressBtn {
  526. if (!_addressBtn) {
  527. _addressBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  528. _addressBtn.titleLabel.numberOfLines = 0;
  529. _addressBtn.titleLabel.font = RQRegularFont_14;
  530. [_addressBtn setBackgroundColor:RQColorFromHexString(@"#232323")];
  531. [_addressBtn setTitleColor:RQColorFromHexString(@"#498EF5") forState:UIControlStateNormal];
  532. }
  533. return _addressBtn;
  534. }
  535. @end