Android 高德地图自定义线路规划选择方案之后按照方案进行导航
因为我这边导航需求的问题,导致我这边不能使用高德地图官方的线路规划和导航。所以我这边线路规划和导航界面都是根据高德地图那边给的api进行自定义的,这篇主要讲我在路线规划方案选择之后按照方案进行导航。
线路规划界面大致是这样的情况,所以我这边就不能像之前那样只做一条路线的查询。
然后我这边开始的时候就用了之前那种获取路径的方法,并且绘制出来。不过这里是多条线路的查询,只需要跟之前传的参数多多路径查询就可以得到高德地图那边返回多条路线的数据。
/**
* 开始搜索路径规划方案 驾车
*/
public void searchRouteResultCar(LatLonPoint mStartPoint, LatLonPoint mEndPoint) {
final RouteSearch.FromAndTo fromAndTo = new RouteSearch.FromAndTo(mStartPoint, mEndPoint);
RouteSearch.DriveRouteQuery query = new RouteSearch.DriveRouteQuery(fromAndTo, 10, null, null, "");
// 第一个参数表示路径规划的起点和终点,第二个参数表示驾车模式 大于等于10 的时候是多路径规划,第三个参数表示途经点,第四个参数表示避让区域,第五个参数表示避让道路
mRouteSearch.calculateDriveRouteAsyn(query);// 异步路径规划驾车模式查询
}
/**
* 开始搜索路径规划方案 步行
*/
public void searchRouteResultWalk(LatLonPoint mStartPoint, LatLonPoint mEndPoint) {
final RouteSearch.FromAndTo fromAndTo = new RouteSearch.FromAndTo(mStartPoint, mEndPoint);
RouteSearch.WalkRouteQuery query = new RouteSearch.WalkRouteQuery(fromAndTo);
mRouteSearch.calculateWalkRouteAsyn(query);// 异步路径规划步行模式查询
}
两种线路搜索步行和驾车,步行返回的只有一种方案,而驾车返回的是最多3中的方案。
线路搜索高德地图的API 想了解详请的可以去看一下
之后就是根据返回的方案在界面上绘制出一种默认选中的路线,点击其他的item,就将当前显示的清除掉,绘制选中的那条线路。(我的做法比较死板,但是也可以将三条都绘制出来,然后将默认选中的那条线路正常颜色绘出,其他未选中的可以这只50%的透明度,这样在界面上就可以看出三种方案。)
线路搜索的监听事件
/**
* 路径规划搜索监听
*/
RouteSearch.OnRouteSearchListener mRouteSearchListener = new RouteSearch.OnRouteSearchListener() {
@Override
public void onBusRouteSearched(BusRouteResult busRouteResult, int i) {
// 公交路径
}
@Override
public void onDriveRouteSearched(DriveRouteResult result, int errorCode) {
// 驾车路径
mAmap.clear();// 清理地图上的所有覆盖物
if (errorCode == AMapException.CODE_AMAP_SUCCESS) {
if (result != null && result.getPaths() != null) {
if (result.getPaths().size() > 0) {
mDriveRouteResult = result;
final DrivePath drivePath = mDriveRouteResult.getPaths().get(0);
if(drivePath == null) {
mIsEmpty = true;
showEmpty();
return;
}
mIsFirstClickCar = false;
mIsEmpty = false;
showEmpty();
mListInfo.clear();
for (int i = 0; i < mDriveRouteResult.getPaths().size(); i++){
mListInfo.add(new SharedNavigationGoHereBean(mDriveRouteResult.getPaths().get(i),i == 0 ? true : false));
}
mAdapter.setDatas(mListInfo);
hideLoading();
SharedGoHereDrivingRouteOverlay drivingRouteOverlay = new SharedGoHereDrivingRouteOverlay(
SharedNavigationGoHereActivity.this, mAmap, drivePath,
mDriveRouteResult.getStartPos(),
mDriveRouteResult.getTargetPos(), null,true);
drivingRouteOverlay.setNodeIconVisibility(false);//设置节点marker是否显示
drivingRouteOverlay.setIsColorfulline(false);//是否用颜色展示交通拥堵情况,默认true
drivingRouteOverlay.removeFromMap();
drivingRouteOverlay.addToMap();
drivingRouteOverlay.zoomToSpan();
dataBinding.rvGuideList.setVisibility(View.VISIBLE);
dataBinding.tvWorkContent.setVisibility(View.GONE);
dataBinding.ivGoGuide.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 进入导航界面
goGuideActivity();
}
});
} else if (result != null && result.getPaths() == null) {
mIsEmpty = true;
showEmpty();
}
} else {
mIsEmpty = true;
showEmpty();
}
} else {
mIsEmpty = true;
showEmpty();
}
}
@Override
public void onWalkRouteSearched(WalkRouteResult result, int errorCode) {
// 步行路径
mAmap.clear();// 清理地图上的所有覆盖物
if (errorCode == AMapException.CODE_AMAP_SUCCESS) { // 需要做缓存 下一次直接切换
if (result != null && result.getPaths() != null) {
if (result.getPaths().size() > 0) {
mWalkRouteResult = result;
final WalkPath walkPath = mWalkRouteResult.getPaths().get(0);
mIsFirstClickWalk = false;
hideLoading();
if(walkPath == null) {
mIsEmpty = true;
showEmpty();
return;
}
mIsEmpty = false;
showEmpty();
WalkRouteOverlay walkRouteOverlay = new WalkRouteOverlay(
SharedNavigationGoHereActivity.this, mAmap, walkPath,
mWalkRouteResult.getStartPos(),
mWalkRouteResult.getTargetPos());
walkRouteOverlay.removeFromMap();
walkRouteOverlay.addToMap();
walkRouteOverlay.zoomToSpan();
dataBinding.tvWorkContent.setVisibility(View.VISIBLE);
int dis = (int) walkPath.getDistance();
int dur = (int) walkPath.getDuration();
String des = AMapUtil.getFriendlyTime(dur)+" "+AMapUtil.getFriendlyLength(dis);
dataBinding.tvWorkContent.setText(des);
dataBinding.rvGuideList.setVisibility(View.GONE);
dataBinding.ivGoGuide.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 进入导航界面
goGuideActivity();
}
});
} else if (result != null && result.getPaths() == null) {
mIsEmpty = true;
showEmpty();
mIsFirstClickWalk = false;
hideLoading();
}
} else {
mIsEmpty = true;
showEmpty();
mIsFirstClickWalk = false;
hideLoading();
}
} else {
mIsEmpty = true;
showEmpty();
mIsFirstClickWalk = false;
hideLoading();
}
}
@Override
public void onRideRouteSearched(RideRouteResult rideRouteResult, int i) {
// 骑行路径
}
};
如果你不会根据自定义的方案,选中之后按照自己选中的进行自定义的导航事件,那么到这里就已经实现了。
这个是我之前的做法,导致后面按照方案导航一直都没有想到要怎么实现选中方案进行导航,然后就有了之后的实现方式,这个跟上面完全不一样。由于跟导航相关,所以跟导航的相关信息挂钩。
在显示方案的界面做导航对象的实例化,它是属于一个单例
/**
* 导航对象(单例)
*/
private AMapNavi mAMapNavi;
然后对导航事件的监听和开始路线搜索:
// 初始化导航对象,由于是单例,所以需要传入Application的Context
mAMapNavi = AMapNavi.getInstance(getApplicationContext());
mAMapNavi.addAMapNaviListener(this);
// 开始计算驾车的情况的路线
int strategyFlag = 0;
try {
// 这个是我保存到本地的算路的时候的一些条件
hightspeed = SPUtils.getInt(SPUtils.GUIDE_GSYX)==1; // 高度优先
avoidhightspeed = SPUtils.getInt(SPUtils.GUIDE_DBGS)==1; // 躲避高速
cost = SPUtils.getInt(SPUtils.GUIDE_DBSF)==1; // 躲避收费
congestion = SPUtils.getInt(SPUtils.GUIDE_DBYD)==1; // 躲避拥堵
// 最后一个传true,表示我需要返回多条路线的值, 传false表示只会返回一条路线
strategyFlag = mAMapNavi.strategyConvert(congestion, avoidhightspeed, cost, hightspeed, true);
} catch (Exception e) {
e.printStackTrace();
}
if (strategyFlag >= 0) {
startList.add(new NaviLatLng(Constants.mLatitude,Constants.mLongitude)); // 从我的位置开始导航
endList.add(new NaviLatLng(mLat,mLng)); // 目的地位置
mAMapNavi.calculateDriveRoute(startList, endList, null, strategyFlag); // 开始计算
}
由于当前初始化的Activity销毁之后就不会再回调导航的状态,所以在进入导航界面一定不能finish掉这个activity。向前创建新的界面到时无所谓,但是我这边还有一个其他的功能,导致向后也需要保存这个界面的存在,所以我将当前activity进行压栈的处理。Activity自带的
moveTaskToBack(true);
@Override
protected void onDestroy() {
super.onDestroy();
/**
* 当前页面只是展示地图,activity销毁后不需要再回调导航的状态
*/
mAMapNavi.removeAMapNaviListener(this);
mAMapNavi.destroy();
}
计算路线成功之后的监听事件,由于导航对象监听事件比较多,我这边就主要讲我使用的几个方法。
@Override // 计算线路返回成功,由于我计算的是多个线路,所以这里是一个集合
public void onCalculateRouteSuccess(int[] ints) {
//清空上次计算的路径列表。
routeOverlays.clear();
HashMap<Integer, AMapNaviPath> paths = mAMapNavi.getNaviPaths();
for (int i = 0; i < ints.length; i++) {
AMapNaviPath path = paths.get(ints[i]);
if (path != null) {
// 将获取的线路绘制到界面上
drawRoutes(ints[i], path);
}
}
}
绘制到界面上
private void drawRoutes(int routeId, AMapNaviPath path) {
calculateSuccess = true;
mAmap.moveCamera(CameraUpdateFactory.changeTilt(0));
RouteOverLay routeOverLay = new RouteOverLay(mAmap, path, this);
// routeOverLay.setTrafficLine(false);
// routeOverLay.zoomToSpan();
// routeOverLay.addToMap();
// 前面的RouteOverLay 也可以正常将线路绘制到界面上,由于我这边绘制的线路有UI样式的实现,所以我这边需要进行自定义实现
// 将获取到的线路保存到缓存中,方便下一次使用
routeOverlays.put(routeId, routeOverLay);
// 判断缓存中的数据数量是否与查询出来的数据数量一致
if (routeOverlays.size() == mAMapNavi.getNaviPaths().size()){ // 一致就开始绘制自己需要的界面
mIsFirstClickCar = false; // 下一次点击驾车就不进行计算,直接从缓存中获取
mIsEmpty = false; // 数据不是空
showEmpty(); // 显示数据不是空的布局
mListInfo.clear(); // 方案列表的数据清空
for (int i = 0; i < routeOverlays.size(); i++){
// 根据key去获取AMapNaviPath的值,防止拿错的情况
int key = routeOverlays.keyAt(i);
// 将当前key值的数据对应的放到list中
mListInfo.add(new SharedNavigationGoHereBeanBack(routeOverlays.get(key).getAMapNaviPath(),i == 0 ? true : false));
}
// 更新界面
mAdapter.setDatas(mListInfo);
// 计算中的动画停止
hideLoading();
// 绘制默认选中的那一条线路 ,这里跟上面差不了太多,只不过里面的类不怎么一样
SharedGoHereDrivingRouteOverlayBackUp drivingRouteOverlay = new SharedGoHereDrivingRouteOverlayBackUp(
SharedNavigationGoHereActivityBackUp.this, mAmap, mListInfo.get(0).getItem(),
new NaviLatLng(Constants.mLatitude,Constants.mLongitude),
new NaviLatLng(mLat,mLng), null,true);
drivingRouteOverlay.setNodeIconVisibility(false);//设置节点marker是否显示
drivingRouteOverlay.setIsColorfulline(false);//是否用颜色展示交通拥堵情况,默认true
drivingRouteOverlay.removeFromMap();
drivingRouteOverlay.addToMap();
drivingRouteOverlay.zoomToSpan();
int key = routeOverlays.keyAt(0);
mAMapNavi.selectRouteId(key);
dataBinding.rvGuideList.setVisibility(View.VISIBLE);
dataBinding.tvWorkContent.setVisibility(View.GONE);
dataBinding.ivGoGuide.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 进入导航界面
goGuideActivity();
}
});
}
}
这个是属于导航对象选择线路的切换。 每一次点击方案的切换都需要调用当前界面显示路线值赋值给导航对象。
如果没有调用这一步,导航对象会默认没有可以导航的路线。
int key = routeOverlays.keyAt(0);
mAMapNavi.selectRouteId(key);
下面是到我自定义的导航界面中,初始化还是跟方案界面的一样初始化,只是在进入到导航界面就可以开始调用开始导航的API了。
mAMapNavi.startNavi(AMapNavi.GPSNaviMode);
这样就可以按照我选择的方案进行导航了。