Files
ln-ios/ln_jq_app/ios/AMapNavIOSSDK/AMapNavIOSSDK/Classes/Class/ARoutePlaneController.m
2026-04-01 15:12:54 +08:00

1187 lines
43 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// ARoutePlaneController.m
// ANavDemo
//
// Created by admin on 2026/2/5.
//
#import "ARoutePlaneController.h"
#import <AMapNaviKit/MAMapKit.h>
#import <AMapNaviKit/AMapNaviKit.h>
#import <AMapLocationKit/AMapLocationKit.h>
#import <AMapSearchKit/AMapSearchAPI.h>
#import "ASearchAddressController.h"
#import "AMapNavSDKManager.h"
#import "AMapPrivacyUtility.h"
#import "AStationDetailPopupController.h"
#define kRouteIndicatorViewHeight 64.f
#import "AMapHyStationModel.h"
#import "AMapNavHttpUtil.h"
#import "ACustomStepView.h"
#import "ABottomBarView.h"
@interface ARoutePlaneController ()<MAMapViewDelegate, AMapNaviDriveManagerDelegate,AMapNaviCompositeManagerDelegate , AMapLocationManagerDelegate , UITextFieldDelegate , AStationDetailPopupDelegate, ABottomBarViewDelegate>
@property (nonatomic, strong) UITextField *textField;
/// 底部搜索+规划路线栏
@property (nonatomic, strong) ABottomBarView *bottomBarView;
@property (nonatomic, strong) MAMapView *mapView;
@property (nonatomic,strong) AMapLocationManager *locationService; //定位服务
/**
* 经纬度
*/
@property (nonatomic, assign) double latitude;
@property (nonatomic, assign) double longitude;
@property (nonatomic, strong) UITextField *startTf;
@property (nonatomic, strong) UITextField *dstTf;
@property (nonatomic, strong) UIButton *navBtn;
@property (nonatomic, strong) AMapPOI *startPoi;
@property (nonatomic, strong) AMapPOI *dstPoi;
@property (nonatomic, strong) AMapPOI *defaultDstPoi; //默认的附近点
@property (nonatomic, strong) AMapNaviCompositeManager *compositeManager;//nav
@property (nonatomic, assign) BOOL calRouteSuccess;
@property (nonatomic, strong) NSDictionary * currentCalRoutePaths;//当前规划的路线
@property (nonatomic , assign)BOOL isStartNav;//开始导航
@property (nonatomic, strong) NSArray * lastOverLays;
@property (nonatomic , strong)NSArray * hyStationArr;//站点数据
@property (nonatomic , assign)BOOL startQueryCurrnetNodeFlag;//开始查询当前节点;
@property (nonatomic , strong)ACustomStepView * stepView;
/// 当前弹出的站点详情弹框
@property (nonatomic , strong)AStationDetailPopupController * stationDetailPopup;
@property (nonatomic, strong) ANavPointModel *pointModel; //当前选的目的点
@property (nonatomic, strong) ATripCalcDataModel * tjdPathInfoModel;//途经点信息
@property (nonatomic, strong) CLLocationManager * locationManager;
@end
@implementation ARoutePlaneController
- (void)viewDidLoad {
[super viewDidLoad];
_startQueryCurrnetNodeFlag = NO;
[self observePrivacyStatus];
[self checkPrivacyStatus];
////
// [self.naviManager independentCalculateDriveRouteWithStartPOIInfo:startPOIInfo
// endPOIInfo:endPOIInfo
// wayPOIInfos:wayPOIInfos
// strategy:AMapNaviDrivingStrategyMultipleDefault
// callback:^(AMapNaviRouteGroup *routeGroup, NSError *error) {
// if (error == nil) {
// // 算路成功routeGroup 包含路线数据
// [self startNaviWithRoute:routeGroup];
// }
// }];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[AMapPrivacyUtility handlePrivacyAgreeStatusIn:self];
}
#pragma mark - request
-(void)requestHyListWithParms:(NSDictionary*)dic {
NSString * url = kGetStationListUrl;
/**
//汽车公园有数据
"longitude": "121.30461400",
"latitude": "31.17321100"
*/
NSDictionary * dic2 = @{@"longitude":@"121.16661700" , @"latitude":@"31.27981600"};
[AMapNavHttpUtil postRequestWithURL:url parameters:dic requestHeader:@{@"Content-Type":@"application/json; charset=UTF-8"} successHandler:^(NSDictionary * _Nonnull data, NSURLResponse * _Nonnull response) {
AMapHyResponse * resp = [AMapHyResponse mj_objectWithKeyValues:data];
if (resp.code == 0 && resp.data) {
NSArray * allData = resp.data;
NSArray * dst = allData;
NSInteger len = allData.count;
if (allData.count > len) {
dst = [resp.data subarrayWithRange:NSMakeRange(0, len)];
}
[self updateMapAnnotationWithData:dst];
}else {
NSLog(@">>>>>>>请求站点:%@" ,resp.message);
}
} failureHandler:^(NSError * _Nonnull error) {
NSLog(@">>>>>>>请求站点err%@" ,error.debugDescription);
}];
}
-(void)requestHyDetailWithParms:(NSDictionary*)dic {
NSString * url = kGetStationDetailtUrl;
[AMapNavHttpUtil postRequestWithURL:url parameters:dic requestHeader:@{@"Content-Type":@"application/json; charset=UTF-8"} successHandler:^(NSDictionary * _Nonnull data, NSURLResponse * _Nonnull response) {
AMapHyResponse * resp = [AMapHyResponse mj_objectWithKeyValues:data];
if (resp.code == 0) {
NSDictionary * resData = data[@"data"];
AMapHyStationModel * station = [AMapHyStationModel mj_objectWithKeyValues:resData];
[self updateHeadAddressWithStation:station];
}else {
NSLog(@">>>>>>>请求站点detail%@" ,resp.message);
}
} failureHandler:^(NSError * _Nonnull error) {
NSLog(@">>>>>>>请求站点err%@" ,error.debugDescription);
}];
}
-(void)requestRoutePathWithParms:(NSDictionary*)dic completeHandle:(void(^)(ATripCalcDataModel * tjd))blk {
NSString * token = [[NSUserDefaults standardUserDefaults]valueForKey:@"flutter.token"];
NSString * carNo = [[NSUserDefaults standardUserDefaults]valueForKey:@"flutter.plateNumber"];
if (stringIsEmpty(token) || stringIsEmpty(carNo)) {
[AMapNavCommonUtil showMsg:@"车牌或token为空请重新登录"]; return;
}
if (stringIsEmpty(self.pointModel.stationID)) {
[AMapNavCommonUtil showMsg:@"站点ID不能为空"]; return;
}
NSMutableDictionary * dic2 = [NSMutableDictionary dictionary];
dic2[@"longitude"] = [NSString stringWithFormat:@"%f" , self.longitude];
dic2[@"latitude"] = [NSString stringWithFormat:@"%f" , self.latitude];
dic2[@"plateNumber"] = carNo;
dic2[@"hydrogenSiteId"] = [NSString stringWithFormat:@"%@" , self.pointModel.stationID];
NSDictionary * headDic = @{
@"Content-Type":@"application/json; charset=UTF-8",
@"asoco-token" : token
};
[AMapNavCommonUtil showLoadingWithMsg:@""];
NSString * url = kGetRoutePointtUrl;
[AMapNavHttpUtil postRequestWithURL:url parameters:dic2 requestHeader:headDic successHandler:^(NSDictionary * _Nonnull data, NSURLResponse * _Nonnull response) {
ATripCalcResponse * resp = [ATripCalcResponse mj_objectWithKeyValues:data];
if (resp.code == 200 && resp.data) {
self.tjdPathInfoModel = resp.data;
if (blk) {
blk(resp.data);
}
}else {
[AMapNavCommonUtil showMsg:data[@"message"]];
}
[AMapNavCommonUtil dismiss];
} failureHandler:^(NSError * _Nonnull error) {
NSLog(@">>>>>>>请求途经点:%@" ,error.debugDescription);
[AMapNavCommonUtil dismiss];
[AMapNavCommonUtil showMsg:error.debugDescription];
}];
}
-(void)updateHeadAddressWithStation:(AMapHyStationModel*)model {
AMapPOI * aoi = [[AMapPOI alloc] init];
aoi.location = [AMapGeoPoint locationWithLatitude:[model.latitude doubleValue] longitude:[model.longitude doubleValue]];
aoi.name = model.name;
aoi.address = model.address;
aoi.uid = model.ID;
self.dstPoi = aoi;
self.defaultDstPoi = [aoi copy];
///地址栏
[self updateUIWithData:aoi textField:self.dstTf];
}
-(void)updateMapAnnotationWithData:(NSArray *)dataArr {
self.hyStationArr = dataArr;
if (!(dataArr && dataArr.count > 0)) {
return;
}
///添加标注
NSMutableArray * points = [NSMutableArray arrayWithCapacity:dataArr.count];
for (AMapHyStationModel * model in dataArr) {
ACustomPointAnnotation *pointAnnotation = [[ACustomPointAnnotation alloc] init];
if (!(model.latitude && model.longitude)) {
continue;
}
pointAnnotation.coordinate = CLLocationCoordinate2DMake([model.latitude doubleValue], [model.longitude doubleValue]);
pointAnnotation.title = model.name;
pointAnnotation.subtitle = model.address;
pointAnnotation.stationID = model.ID;
[points addObject:pointAnnotation];
}
// 1. 先获取当前地图区域
// MACoordinateRegion currentRegion = self.mapView.region;
// 2. 添加标注但不改变地图显示
[self.mapView addAnnotations:points];
// 保持地图中心点为当前位置
if (self.latitude && self.longitude) {
[self.mapView setCenterCoordinate: CLLocationCoordinate2DMake(self.latitude, self.longitude) animated:YES];
}
// 3. 保持当前区域不变
// [self.mapView setRegion:currentRegion animated:NO];
}
#pragma mark - init
-(void)initSubview {
// ── 地图全屏 ─────────────────────────────────────────────
[self.mapView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.view);
}];
// ── 底部栏(搜索框 + 规划路线按钮) ──────────────────────
ABottomBarView *bottomBar = [[ABottomBarView alloc] init];
bottomBar.delegate = self;
[self.view addSubview:bottomBar];
self.bottomBarView = bottomBar;
[bottomBar mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.equalTo(self.view);
make.bottom.equalTo(self.view);
}];
// ── 兼容旧逻辑:保留 startTf / dstTf 属性(隐藏,不再显示) ──
// startTf/dstTf 只用作数据载体,不加入视图层级
UITextField *startTf = [[UITextField alloc] init];
startTf.tag = 100;
self.startTf = startTf;
UITextField *dstTf = [[UITextField alloc] init];
dstTf.tag = 200;
self.dstTf = dstTf;
// ── 旧版导航按钮保留hidden 状态,供兼容逻辑使用) ─────
UIButton *navBtn = [UIButton buttonWithType:UIButtonTypeCustom];
navBtn.hidden = YES;
[navBtn addTarget:self action:@selector(navAction) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:navBtn];
[navBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self.view).offset(-15);
make.bottom.equalTo(self.view).offset(-118);
make.height.mas_equalTo(@30);
make.width.mas_equalTo(@60);
}];
[self.view bringSubviewToFront:bottomBar];
// ── 放大缩小控件 ──────────────────────────────────────────
ACustomStepView *stepView = [[ACustomStepView new] initWithValue:self.mapView.zoomLevel maxValue:18.5 min:3.5];
[self.view addSubview:stepView];
[stepView mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self.view).offset(-15);
make.width.equalTo(@40);
make.height.equalTo(@81);
make.top.equalTo(self.view).offset(100);
}];
[stepView addObserver:self forKeyPath:@"value" options:NSKeyValueObservingOptionNew context:nil];
self.stepView = stepView;
///当前位置按钮
UIButton * btn = [UIButton buttonWithType:UIButtonTypeCustom];
[btn setImage:[AMapNavCommonUtil imageWithName3x:@"my_location_icon"] forState:UIControlStateNormal];
btn.backgroundColor = [UIColor lightGrayColor];
btn.titleLabel.font = [UIFont systemFontOfSize:14];
btn.layer.cornerRadius = 20;
[btn addTarget:self action:@selector(updateUserLocalAction) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
[btn mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self.view).offset(-10);
make.width.height.equalTo(@40);
make.bottom.equalTo(bottomBar.mas_top).offset(-85);
}];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
if ([keyPath isEqualToString:@"value"]) {
self.mapView.zoomLevel = [change[NSKeyValueChangeNewKey] doubleValue];
}
}
- (void)initDriveManager
{
//请在 dealloc 函数中执行 [AMapNaviDriveManager destroyInstance] 来销毁单例
[[AMapNaviDriveManager sharedInstance] setDelegate:self];
}
- (void)initMapView
{
if (self.mapView == nil)
{
self.mapView = [[MAMapView alloc] initWithFrame:CGRectZero];
[self.mapView setDelegate:self];
self.mapView.showsUserLocation = YES;
self.mapView.userTrackingMode = MAUserTrackingModeFollowWithHeading;
self.mapView.desiredAccuracy = kCLLocationAccuracyNearestTenMeters; // 定位精度
_mapView.showsScale= YES;
_mapView.logoCenter = CGPointMake(CGRectGetWidth(self.view.bounds)-55, 450);
self.mapView.zoomLevel = 11;
// 4. 禁用自动调整
// [self.mapView setAutoCheckMapBoundary:NO];
[self.view addSubview:self.mapView];
if (@available(iOS 14.0, *)) {
// iOS14+ 需要额外处理
CLAuthorizationStatus status = [[[CLLocationManager alloc] init] authorizationStatus];
if (status == kCLAuthorizationStatusNotDetermined) {
[[[CLLocationManager alloc] init] requestWhenInUseAuthorization];
}
}
}
}
-(void)updateUserLocalAction {
// 如果已经有位置,直接移动视角
if (_mapView.userLocation.location) {
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(self.latitude, self.longitude);
[_mapView setCenterCoordinate:coord animated:YES];
// [_mapView setZoomLevel:10 animated:YES];
} else {
// 如果尚未获取到位置,进入跟踪模式等待回调
[_mapView setUserTrackingMode:MAUserTrackingModeFollow animated:YES];
}
}
- (void)initAnnotations
{
NaviPointAnnotation *beginAnnotation = [[NaviPointAnnotation alloc] init];
[beginAnnotation setCoordinate:CLLocationCoordinate2DMake(self.startPoi.location.latitude, self.startPoi.location.longitude)];
beginAnnotation.title = @"起始点";
beginAnnotation.navPointType = NaviPointAnnotationStart;
[self.mapView addAnnotation:beginAnnotation];
// NaviPointAnnotation *endAnnotation = [[NaviPointAnnotation alloc] init];
// [endAnnotation setCoordinate:CLLocationCoordinate2DMake(self.dstPoi.location.latitude, self.dstPoi.location.longitude)];
// endAnnotation.title = @"终点";
// endAnnotation.navPointType = NaviPointAnnotationEnd;
//
// [self.mapView addAnnotation:endAnnotation];
}
- (AMapLocationManager *)locationService {
if (!_locationService) {
_locationService = [[AMapLocationManager alloc] init];
_locationService.delegate = self;
_locationService.desiredAccuracy = kCLLocationAccuracyBestForNavigation; // 最高精度模式
_locationService.distanceFilter = 5;
_locationService.locatingWithReGeocode = YES;
// CLLocationManager * mgr;
// // 2. 检查是否为模糊定位iOS 14+
// if (@available(iOS 14.0, *)) {
// if (mgr.accuracyAuthorization == CLAccuracyAuthorizationReducedAccuracy) {
// // 弹窗申请临时精确权限(需配置 purposeKey
// [mgr requestTemporaryFullAccuracyAuthorizationWithPurposeKey:@"YourPurposeKey" completion:nil];
//
// }
// }
}
return _locationService;
}
- (void)dealloc {
[self.locationService stopUpdatingLocation];
[self.stepView removeObserver:self forKeyPath:@"value"];
}
- (AMapNaviCompositeManager *)compositeManager {
if (!_compositeManager) {
_compositeManager = [[AMapNaviCompositeManager alloc] init]; // 初始化
_compositeManager.delegate = self; // 如果需要使用AMapNaviCompositeManagerDelegate的相关回调如自定义语音、获取实时位置等需要设置delegate
}
return _compositeManager;
}
// 监听隐私状态变化
- (void)observePrivacyStatus {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handlePrivacyUpdate)
name:@"ksAMapPrivacyDidUpdateNotification" // 自定义通知
object:nil];
}
-(void)handlePrivacyUpdate {
[self checkPrivacyStatus];
}
// 检查当前隐私状态
- (void)checkPrivacyStatus {
BOOL hasAgreed = [[NSUserDefaults standardUserDefaults] boolForKey:@"usragreeStatus"];
if (hasAgreed) {
/// 开启定位
[self.locationService startUpdatingLocation];
// [self.mapView reloadMap];
[self initMapView];
[self initSubview];
[self initDriveManager];
} else {
}
}
#pragma mark - 计算线路
///计算线路
-(void)calRoutePathWithWayPonts:(NSArray<ANaviPathInfoModel *> *) naviList {
AMapNaviPoint * startPoint = [AMapNaviPoint locationWithLatitude:self.startPoi.location.latitude longitude:self.startPoi.location.longitude];
AMapPOI *_dstPoi = self.dstPoi ? self.dstPoi : self.defaultDstPoi;
AMapNaviPoint * endPoint = [AMapNaviPoint locationWithLatitude:_dstPoi.location.latitude longitude:_dstPoi.location.longitude];
if (!(self.startPoi && _dstPoi)) {
[AMapNavCommonUtil showMsg:@"计算线路,起始点缺失"];
return;
}
AMapNaviDrivingStrategy strategy = ConvertDrivingPreferenceToDrivingStrategy(0,
0,
0,
0,
0);
strategy = AMapNaviDrivingStrategyMultipleDefault;//使用默认策略
id delegate = [AMapNaviDriveManager sharedInstance].delegate;
if (!delegate) {
[AMapNaviDriveManager sharedInstance].delegate = self;
}
NSArray<AMapNaviPoint *> *wayPoints = [self getWayPointWithPoint:naviList];
[[AMapNaviDriveManager sharedInstance] setVehicleInfo:[self getCarInfo]];
[[AMapNaviDriveManager sharedInstance] calculateDriveRouteWithStartPoints:@[startPoint]
endPoints:@[endPoint]
wayPoints:wayPoints
drivingStrategy:strategy];
}
-(NSArray *)getWayPointWithPoint:(NSArray<ANaviPathInfoModel *> *) naviList {
NSMutableArray <AMapNaviPoint *> *wayPoints = [NSMutableArray array];
for (int i = 0; i < naviList.count; i++) {
ANaviPathInfoModel * item = naviList[i];
AMapNaviPoint * res = [AMapNaviPoint locationWithLatitude:[item.latitude doubleValue] longitude:[item.longitude doubleValue]];
[wayPoints addObject:res];
}
return wayPoints;
}
-(AMapNaviVehicleInfo*)getCarInfo {
AMapNaviVehicleInfo * car = [AMapNaviVehicleInfo new];
ATruckModel * truckInfo = self.tjdPathInfoModel.truckDto;
if (!truckInfo) {
return car;
}
// 车牌号
if (truckInfo.mcarNumber.length > 0) {
car.vehicleId = truckInfo.mcarNumber;
}
// 是否躲避限行
car.isETARestriction = truckInfo.isRestriction;
// 车辆类型mcarType 与高德 type 定义一致)
car.type = truckInfo.mcarType;
// 货车大小分类mvehicleSize4 = 重型货车,对应高德 size:4
car.size = truckInfo.mvehicleSize;
// 轴数
car.axisNums = truckInfo.mvehicleAxis;
// 车身宽度(单位:米)
if (truckInfo.mvehicleWidth.length > 0) {
car.width = [[NSDecimalNumber decimalNumberWithString:truckInfo.mvehicleWidth] floatValue];
}
// 车身高度(单位:米)
if (truckInfo.mvehicleHeight.length > 0) {
car.height = [[NSDecimalNumber decimalNumberWithString:truckInfo.mvehicleHeight] floatValue];
}
// 车身长度(单位:米)
if (truckInfo.mvehicleLength.length > 0) {
car.length = [[NSDecimalNumber decimalNumberWithString:truckInfo.mvehicleLength] floatValue];
}
//总重
if (truckInfo.mvehicleLoad.length > 0) {
car.load = [[NSDecimalNumber decimalNumberWithString:truckInfo.mvehicleLoad] floatValue];
}
// 核定载重
if (truckInfo.mvehicleWeight.length > 0) {
car.weight = [[NSDecimalNumber decimalNumberWithString:truckInfo.mvehicleWeight] floatValue];
}
return car;
}
///算路成功后回调
- (void)driveManagerOnCalculateRouteSuccess:(AMapNaviDriveManager *)driveManager
{
NSDictionary * lines = [AMapNaviDriveManager sharedInstance].naviRoutes ;
NSLog(@"onCalculateRouteSuccess:%@" , lines);
//算路成功后显示路径
[self gd_navWithCalulatedPath];
}
- (void)driveManager:(AMapNaviDriveManager *)driveManager error:(NSError *)error {
///算路失败,直接去高德规划页面
[self gd_calPathWithNoStationId:self.pointModel];
}
#pragma mark 显示线路[废弃]
- (void)showNaviRoutes
{
if ([[AMapNaviDriveManager sharedInstance].naviRoutes count] <= 0)
{
return;
}
self.lastOverLays = self.mapView.overlays;
[self.mapView removeOverlays:self.mapView.overlays];
// [self.routeIndicatorInfoArray removeAllObjects];
self.currentCalRoutePaths = [AMapNaviDriveManager sharedInstance].naviRoutes;
NSInteger routeId = 0;
//将路径显示到地图上
for (NSNumber *aRouteID in [[AMapNaviDriveManager sharedInstance].naviRoutes allKeys])
{
AMapNaviRoute *aRoute = [[[AMapNaviDriveManager sharedInstance] naviRoutes] objectForKey:aRouteID];
int count = (int)[[aRoute routeCoordinates] count];
//添加路径Polyline
CLLocationCoordinate2D *coords = (CLLocationCoordinate2D *)malloc(count * sizeof(CLLocationCoordinate2D));
for (int i = 0; i < count; i++)
{
AMapNaviPoint *coordinate = [[aRoute routeCoordinates] objectAtIndex:i];
coords[i].latitude = [coordinate latitude];
coords[i].longitude = [coordinate longitude];
}
// SelectableOverlay 继承 MAPolyline直接用坐标初始化避免 renderer overlay 不匹配警告
SelectableOverlay *selectablePolyline = [SelectableOverlay overlayWithCoordinates:coords count:count];
selectablePolyline.routeID = [aRouteID integerValue];
[self.mapView addOverlay:selectablePolyline];
free(coords);
routeId = [aRouteID integerValue];
}
// 1. 先获取当前地图区域
MACoordinateRegion currentRegion = self.mapView.region;
[self.mapView showAnnotations:self.mapView.annotations animated:NO];
// 3. 保持当前区域不变
[self.mapView setRegion:currentRegion animated:NO];
[self selectNaviRouteWithID:routeId];
///如果已开始导航,直接进入导航
// if (self.isStartNav) {
// [self gd_navWithCalulatedPath];
// }
}
- (void)selectNaviRouteWithID:(NSInteger)routeID
{
//在开始导航前进行路径选择
if ([[AMapNaviDriveManager sharedInstance] selectNaviRouteWithRouteID:routeID])
{
[self selecteOverlayWithRouteID:routeID];
}
else
{
NSLog(@"路径选择失败!");
}
}
- (void)selecteOverlayWithRouteID:(NSInteger)routeID
{
[self.mapView.overlays enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id<MAOverlay> overlay, NSUInteger idx, BOOL *stop)
{
if ([overlay isKindOfClass:[SelectableOverlay class]])
{
SelectableOverlay *selectableOverlay = overlay;
/* 获取overlay对应的renderer. */
MAPolylineRenderer * overlayRenderer = (MAPolylineRenderer *)[self.mapView rendererForOverlay:selectableOverlay];
if (selectableOverlay.routeID == routeID)
{
/* 设置选中状态. */
selectableOverlay.selected = YES;
/* 修改renderer选中颜色. */
overlayRenderer.fillColor = selectableOverlay.selectedColor;
overlayRenderer.strokeColor = selectableOverlay.selectedColor;
/* 修改overlay覆盖的顺序. */
[self.mapView exchangeOverlayAtIndex:idx withOverlayAtIndex:self.mapView.overlays.count - 1];
}
else
{
/* 设置选中状态. */
selectableOverlay.selected = NO;
/* 修改renderer选中颜色. */
overlayRenderer.fillColor = selectableOverlay.regularColor;
overlayRenderer.strokeColor = selectableOverlay.regularColor;
}
}
}];
}
#pragma mark - 导航
///选择方式
-(void)navAction {
[self gd_navWithCalulatedPath]; //直接导航
}
-(void)showSelectNavType {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"选择导航类型" message:nil preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction *sure = [UIAlertAction actionWithTitle:@"SDK导航" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[self gd_navWithCalulatedPath];
}];
UIAlertAction *sure2 = [UIAlertAction actionWithTitle:@"高德地图导航" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[self navigationType_app];
}];
UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
}];
[alert addAction:sure];
[alert addAction:sure2];
[alert addAction:cancel];
[self presentViewController:alert animated:YES completion:nil];
}
-(void)navigationType_app {
NSURL* scheme = [NSURL URLWithString:@"iosamap://"];
BOOL canOpen = [[UIApplication sharedApplication] canOpenURL:scheme];
if (!canOpen) {
[self showAlertWithMessage:@"请先安装高德地图客户端"]; return;
}
NSString *myLocationScheme = [NSString stringWithFormat:@"iosamap://navi?sourceApplication=ANavDemo&lat=31.2304&lon=121.4737&t=0&dev=1"];
NSString *encodedUrlString = [myLocationScheme stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
NSURL *gaodeUrl = [NSURL URLWithString:encodedUrlString];
[[UIApplication sharedApplication] openURL:gaodeUrl options:@{} completionHandler:^(BOOL res) {
}];
}
///使用算好的路,直接导航
-(void)gd_navWithCalulatedPath {
id delegate = [AMapNaviDriveManager sharedInstance].delegate;
if (!delegate) {
[AMapNaviDriveManager sharedInstance].delegate = self;
}
AMapNaviCompositeUserConfig *config = [[AMapNaviCompositeUserConfig alloc] init];
[config setRoutePlanPOIType:AMapNaviRoutePlanPOITypeStart location:[AMapNaviPoint locationWithLatitude:self.startPoi.location.latitude longitude:self.startPoi.location.longitude] name:self.startPoi.name POIId:nil];
///车辆信息
[config setVehicleInfo:[self getCarInfo]];
//直接进入导航,不在算路
[config setStartNaviDirectly:YES]; //直接进入导航界面
[config setNeedCalculateRouteWhenPresent:NO];//不在算路
[config setMultipleRouteNaviMode:NO];//直接单线路径导航
// [config setNeedDestoryDriveManagerInstanceWhenDismiss:NO];
[self.compositeManager presentRoutePlanViewControllerWithOptions:config];
}
///SDK计算线路
-(void)gd_calPathWithNoStationId: (ANavPointModel *) dst {
AMapNaviCompositeUserConfig *config = [[AMapNaviCompositeUserConfig alloc] init];
[config setRoutePlanPOIType:AMapNaviRoutePlanPOITypeEnd location:[AMapNaviPoint locationWithLatitude:dst.coordinate.latitude longitude:dst.coordinate.longitude] name:dst.name POIId:nil];
[config setVehicleInfo:[self getCarInfo]];
// [config setStartNaviDirectly:YES]; //直接进入导航界面
[config setNeedCalculateRouteWhenPresent:NO];//不在算路
// [config setMultipleRouteNaviMode:NO];//直接单线路径导航
// [config setNeedDestoryDriveManagerInstanceWhenDismiss:NO];
[self.compositeManager presentRoutePlanViewControllerWithOptions:config];
}
#pragma mark - AMapLocationManagerDelegate
- (void)amapLocationManager:(AMapLocationManager *)manager didUpdateLocation:(CLLocation *)location reGeocode:(AMapLocationReGeocode *)reGeocode
{
if (!location) {
return;
}
self.latitude = location.coordinate.latitude;
self.longitude = location.coordinate.longitude;
AMapNavSDKManager * sdk = [AMapNavSDKManager sharedManager];
sdk.localCity = reGeocode.city;
sdk.locationAddressDetail = reGeocode.POIName;
// 设置地图中心为用户位置
// MACoordinateRegion region = MACoordinateRegionMake(location.coordinate,
// MACoordinateSpanMake(0.1, 0.1));
// [self.mapView setRegion:region animated:YES];
//更新出发点
AMapPOI * aoi = [[AMapPOI alloc] init];
#ifdef kAMapSDKDebugFlag
aoi.location = [AMapGeoPoint locationWithLatitude:31.23 longitude:121.48 ];
aoi.name =@"人民大道185号";
self.latitude = 31.23;
self.longitude = 121.48 ;
#else
aoi.location = [AMapGeoPoint locationWithLatitude:self.latitude longitude:self.longitude ];
aoi.name = reGeocode.POIName;
#endif
self.startPoi = aoi;
[self updateUIWithData:aoi textField:self.startTf];
//获取附近站点
if (!self.startQueryCurrnetNodeFlag && reGeocode) {
self.startQueryCurrnetNodeFlag = YES;
NSString * province = reGeocode.province;
NSString * city = reGeocode.city;
NSString * district = reGeocode.district;
NSString * longitude = [NSString stringWithFormat:@"%f",self.longitude];
NSString * latitude = [NSString stringWithFormat:@"%f",self.latitude];
if (province && city && district) {
NSDictionary * dic = @{@"province":province , @"city":city , @"district":district , @"longitude":longitude , @"latitude":latitude};
[self requestHyDetailWithParms:dic];
}
[self requestHyListWithParms:@{@"longitude":longitude , @"latitude":latitude}];
}
}
#pragma mark - MAMapView 渲染
- (MAAnnotationView *)mapView:(MAMapView *)mapView viewForAnnotation:(id<MAAnnotation>)annotation
{
// 当前位置:用 car 图标替换系统默认蓝点
if ([annotation isKindOfClass:[MAUserLocation class]])
{
static NSString *userLocationIdentifier = @"UserLocationCarIdentifier";
MAAnnotationView *userView = [mapView dequeueReusableAnnotationViewWithIdentifier:userLocationIdentifier];
if (userView == nil)
{
userView = [[MAAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:userLocationIdentifier];
userView.canShowCallout = NO;
}
else
{
userView.annotation = annotation;
}
userView.image = [AMapNavCommonUtil imageWithName:@"car"];
return userView;
}
if ([annotation isKindOfClass:[NaviPointAnnotation class]])
{
static NSString *annotationIdentifier = @"NaviPointAnnotationIdentifier";
MAPinAnnotationView *pointAnnotationView = (MAPinAnnotationView*)[self.mapView dequeueReusableAnnotationViewWithIdentifier:annotationIdentifier];
if (pointAnnotationView == nil)
{
pointAnnotationView = [[MAPinAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:annotationIdentifier];
}
pointAnnotationView.animatesDrop = NO;
pointAnnotationView.canShowCallout = YES;
pointAnnotationView.draggable = NO;
NaviPointAnnotation *navAnnotation = (NaviPointAnnotation *)annotation;
if (navAnnotation.navPointType == NaviPointAnnotationStart)
{
[pointAnnotationView setPinColor:MAPinAnnotationColorGreen];
}
else if (navAnnotation.navPointType == NaviPointAnnotationEnd)
{
[pointAnnotationView setPinColor:MAPinAnnotationColorRed];
}
return pointAnnotationView;
}
// 处理普通点标注(排除用户定位点)
if ([annotation isKindOfClass:[ACustomPointAnnotation class]] &&
![annotation isKindOfClass:[MAUserLocation class]])
{
static NSString *pointReuseIndentifier = @"pointReuseIndentifier";
ACustomAnnotationView *annotationView = (ACustomAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:pointReuseIndentifier];
if (annotationView == nil)
{
annotationView = [[ACustomAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:pointReuseIndentifier];
}
else
{
// 复用时必须更新 annotation否则可能不刷新/不显示
annotationView.annotation = annotation;
}
// annotationView.canShowCallout= YES; //设置气泡可以弹出默认为NO
// annotationView.animatesDrop = NO; //设置标注动画显示默认为NO
// annotationView.draggable = NO; //设置标注可以拖动默认为NO
// annotationView.pinColor = MAPinAnnotationColorPurple;
// 设置自定义的气泡背景色
if (@available(iOS 14.0, *)) {
// iOS 14+ 可以使用 tintColor
annotationView.tintColor = [UIColor systemBlueColor];
} else {
// iOS 13 及以下
annotationView.tintColor = [UIColor colorWithRed:0.1 green:0.6 blue:0.9 alpha:1.0];
}
return annotationView;
}
return nil;
}
- (MAOverlayRenderer *)mapView:(MAMapView *)mapView rendererForOverlay:(id<MAOverlay>)overlay
{
if ([overlay isKindOfClass:[SelectableOverlay class]])
{
SelectableOverlay *selectableOverlay = (SelectableOverlay *)overlay;
// SelectableOverlay 继承自 MAPolyline直接用自身初始化 renderer
// renderer.overlay == overlay避免 MAMapKit 的 overlay 不匹配警告
MAPolylineRenderer *polylineRenderer = [[MAPolylineRenderer alloc] initWithPolyline:selectableOverlay];
polylineRenderer.lineWidth = 8.f;
polylineRenderer.strokeColor = selectableOverlay.isSelected ? selectableOverlay.selectedColor : selectableOverlay.regularColor;
return polylineRenderer;
}
return nil;
}
// 当地图添加完标注视图后调用
- (void)mapView:(MAMapView *)mapView didAddAnnotationViews:(NSArray *)views {
// 遍历所有被添加的标注视图
# if 0
for (MAAnnotationView *view in views) {
// 检查是否为需要的标注类型,例如大头针标注
if ([view.annotation isMemberOfClass:[ACustomPointAnnotation class]]) {
// 延迟零点几秒执行,以确保视图添加动画完成(可选,但可使效果更平滑)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 选中该标注,从而使其气泡弹出
[mapView selectAnnotation:view.annotation animated:YES];
});
}
}
#endif
}
- (void)mapView:(MAMapView *)mapView didSelectAnnotationView:(MAAnnotationView *)view {
id pointAnnotation = view.annotation;
if ([pointAnnotation isMemberOfClass:ACustomPointAnnotation.class]) {
ACustomPointAnnotation *point = (ACustomPointAnnotation *)view.annotation;
NSLog(@"point: %@" , point.title);
AMapPOI * aoi = [[AMapPOI alloc] init];
aoi.location = [AMapGeoPoint locationWithLatitude:point.coordinate.latitude longitude:point.coordinate.longitude];
aoi.name = point.title;
aoi.address = point.subtitle;
aoi.uid = point.stationID;
self.dstPoi = aoi;
[self updateUIWithData:aoi textField:self.dstTf];
// 同步更新底部栏目的地文字
self.bottomBarView.destinationText = aoi.name;
}
}
// 当标注被取消选中时调用
- (void)mapView:(MAMapView *)mapView didDeselectAnnotationView:(MAAnnotationView *)view {
if ([view.annotation isMemberOfClass:[ACustomPointAnnotation class]]) {
// 清空目的地信息 & 底部栏
self.dstPoi = nil;
self.dstTf.text = nil;
self.bottomBarView.destinationText = nil;
}
}
//选中一个点
- (void)mapView:(MAMapView *)mapView didAnnotationViewCalloutTapped:(MAAnnotationView *)view {
id pointAnnotation = view.annotation;
if ([pointAnnotation isMemberOfClass:ACustomPointAnnotation.class]) {
ACustomPointAnnotation *point = (ACustomPointAnnotation *)view.annotation;
NSLog(@"point: %@" , point.title);
AMapPOI * aoi = [[AMapPOI alloc] init];
aoi.location = [AMapGeoPoint locationWithLatitude:point.coordinate.latitude longitude:point.coordinate.longitude];
aoi.name = point.title;
self.dstPoi = aoi;
[self updateUIWithData:aoi textField:self.dstTf];
}
NSLog(@"didSelectAnnotationView: %s" , __func__);
}
#pragma mark - AMapNaviCompositeManagerDelegate
- (void)compositeManager:(AMapNaviCompositeManager *)compositeManager didStartNavi:(AMapNaviMode)naviMode {
}
- (void)compositeManager:(AMapNaviCompositeManager *)compositeManager onDriveStrategyChanged:(AMapNaviDrivingStrategy)driveStrategy {
NSLog(@"%s" , __func__ );
}
#pragma mark - 弹框
-(void)willRequestTJDInfo {
///调用接口获取途经点
///
AMapPOI *_dstPoi = self.dstPoi ? self.dstPoi : self.defaultDstPoi;
if (!_dstPoi) {
return;
}
AMapGeoPoint * point = _dstPoi.location;
ANavPointModel *navPoint = [ANavPointModel instanceWithCoordinate:CLLocationCoordinate2DMake(point.latitude, point.longitude)
name:_dstPoi.name
address:_dstPoi.address];
navPoint.stationID = _dstPoi.uid;
self.pointModel = navPoint;
///有_stationID 请求接口;无:不走接口,直接调整高德规划路线;
if (!navPoint.stationID) {
[self gd_calPathWithNoStationId:navPoint];
return;
}else {
__weak typeof(self) weakSelf = self;
[self requestRoutePathWithParms:nil completeHandle:^(ATripCalcDataModel *tjd) {
[weakSelf showDstInfoPop:navPoint];
}];
}
}
-(void)showDstInfoPop:(ANavPointModel *) navPoint {
// --- 弹出站点详情弹框 ---
if (!self.stationDetailPopup) {
AStationDetailPopupController *popup = [[AStationDetailPopupController alloc] init];
popup.delegate = self;
self.stationDetailPopup = popup;
}
self.stationDetailPopup.pointModel = navPoint;
///费用
self.stationDetailPopup.estimatedCost = self.tjdPathInfoModel.algorithmPath.hydrogenCost;
///时间
self.stationDetailPopup.estimatedTime = [NSString stringWithFormat:@"%.f" , self.tjdPathInfoModel.pathDto.duration / 60.0];
///距离
self.stationDetailPopup.driveDistance = [NSString stringWithFormat:@"%.1f" , self.tjdPathInfoModel.pathDto.distance / 1000.0] ;
///油费
self.stationDetailPopup.tollFee = self.tjdPathInfoModel.pathDto.tolls;
[self.stationDetailPopup presentInViewController:self];
}
#pragma mark - AStationDetailPopupDelegate
- (void)stationDetailPopupDidTapStartNavi:(AStationDetailPopupController *)popup {
self.stationDetailPopup = nil;
///点击开始导航:
///1、有途经点计算路线然后再直接导航
///2、没有途经点不用计算路线直接跳转高德规划页面然后规划页面中点击导航
ATripCalcDataModel * tjd = self.tjdPathInfoModel;
if (tjd && tjd.pathDto && tjd.pathDto.naviList) {
NSArray * arr = tjd.pathDto.naviList;
if ([arr isKindOfClass:NSArray.class] && arr.count > 0) {
[self calRoutePathWithWayPonts:arr];
}else {
[self gd_calPathWithNoStationId:self.pointModel];
}
}else {
[self gd_calPathWithNoStationId:self.pointModel];
}
}
- (void)stationDetailPopupDidTapClose:(AStationDetailPopupController *)popup {
self.stationDetailPopup = nil;
}
#pragma mark - ABottomBarViewDelegate
- (void)bottomBarViewDidTapCalRoute:(ABottomBarView *)barView {
//详情弹框
[self willRequestTJDInfo];
}
- (void)bottomBarViewDidTapSearchField:(ABottomBarView *)barView {
// 弹出地址搜索页,选中后更新目的地输入框
ASearchAddressController *vc = [[ASearchAddressController alloc] init];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];
nav.modalPresentationStyle = UIModalPresentationFullScreen;
__weak typeof(self) weakSelf = self;
vc.selectAddressBlk = ^(AMapPOI *poi) {
__strong typeof(weakSelf) strongSelf = weakSelf;
// 更新底部栏显示文字
strongSelf.bottomBarView.destinationText = poi.name;
// 同步旧属性(供 calRoutePath 使用)
poi.uid = nil;
[strongSelf updateUIWithData:poi textField:strongSelf.dstTf];
};
[self presentViewController:nav animated:YES completion:nil];
}
-(void)updateUIWithData: (AMapPOI*)poi textField: (UITextField*)tf {
BOOL isStart = tf.tag == 100;
tf.text = poi.name;
if (isStart) {
self.startPoi = poi;
}else {
self.dstPoi = poi;
}
}
#pragma mark - tool
-(void)showAlertWithMessage:(NSString *)msg {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:msg preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *sure = [UIAlertAction actionWithTitle:@"知道了" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
}];
[alert addAction:sure];
[self.navigationController presentViewController:alert animated:YES completion:nil];
}
@end