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);
這樣就可以按照我選擇的方案進行導航了。