百度地圖API製作類似 百度地圖的路線導航介面並實現簡單的路線規劃功能
阿新 • • 發佈:2019-02-12
之前我們講了怎麼在百度地圖上設定Marker(如A點。。) 和彈出框(跟隨Marker的,Marker移動的時候也是會跟著移動的),接著又覺得百度地圖自帶的放大縮小不(fei)是(chang)很(de)漂(chou)亮,我們自定義了放大縮小的控制元件,本篇我們將製作類似百度地圖API製作類似百度地圖的公交/駕車/行走/查詢介面並實現簡單的路線規劃功能。
先來張截圖:
這個介面的實現其實是使用的SlidingUpPanelLayout 開源庫從而使得可以跟隨手指下拉上劃:
其實佈局也沒什麼好講的,自己到百度地圖的APK包裡扒拉扒拉圖片就都有了,哈哈
<?xml version="1.0" encoding="utf-8"?> <com.jsbtclient.cusViews.SlidingUpPanelLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:sothree="http://schemas.android.com/apk/res-auto" android:id="@+id/map_sliding_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="bottom" sothree:umanoPanelHeight="60dp" sothree:umanoShadowHeight="4dp" > <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" > <com.baidu.mapapi.map.MapView android:id="@+id/map_mapView" android:layout_width="match_parent" android:layout_height="match_parent" android:apiKey="vNQtC8sQSODsLGBk01HYaBQt" android:clickable="true" /> <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" > <com.jsbtclient.cusViews.ZoomControlView android:id="@+id/map_zoomcontrol" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right" android:layout_marginBottom="20dp" android:layout_marginRight="15dp" > </com.jsbtclient.cusViews.ZoomControlView> <ImageView android:id="@+id/map_relocation" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="left|top" android:layout_marginLeft="15dp" android:layout_marginTop="5dp" android:background="@drawable/map_relocation_bg" android:src="@drawable/baidu_map_relocation" /> </FrameLayout> </RelativeLayout> <LinearLayout android:id="@+id/map_slidePanel" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="10dp" > <LinearLayout android:id="@+id/slidingdrawer_menu" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:padding="10dp" > <ImageView android:id="@+id/map_route_bus" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:src="@drawable/map_route_bus_selector" /> <ImageView android:id="@+id/map_route_car" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:src="@drawable/map_route_car_selector" /> <ImageView android:id="@+id/map_route_walk" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:src="@drawable/map_route_walk_selector" /> <TextView android:id="@+id/map_route_search" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_weight="1" android:text="@string/map_route_search" android:textColor="@color/call_fragment_bg_color" android:textSize="16sp" /> </LinearLayout> <View android:layout_width="match_parent" android:layout_height="0.1dp" android:background="@color/lightgray" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/white_shadow_bg" android:orientation="horizontal" android:padding="10dp" > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:layout_gravity="center_vertical" android:orientation="vertical"> <ImageView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:src="@drawable/map_route_start" /> <ImageView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:src="@drawable/map_route_end" /> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="8" android:orientation="vertical" android:padding="10dp" > <EditText android:id="@+id/map_my_address" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:background="@null" android:text="@string/map_my_address" android:textColor="@color/lightgrey" android:textSize="16sp" /> <View android:layout_width="match_parent" android:layout_height="0.1dp" android:layout_marginBottom="20dp" android:layout_marginTop="20dp" android:background="@color/lightgray" /> <EditText android:id="@+id/map_target_address" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:background="@null" android:text="@string/map_company_address" android:textColor="@color/call_fragment_bg_color" android:textSize="16sp" /> </LinearLayout> <ImageView android:id="@+id/map_route_exchange" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_weight="1" android:src="@drawable/route_exchange" /> </LinearLayout> </LinearLayout> </com.jsbtclient.cusViews.SlidingUpPanelLayout>
UI上的事就不重點說了,功能實現才是重點:
我們來理一下思路使用者當前的位置是使用百度地圖定位獲取的,而目標位置則應該是使用者自己輸入的,我這裡的實現比較簡單,目的地或者出發地點是固定的就是公司地址,
但是原理是相同的只不過少一次網路請求而已。 現在假設使用者目的地是指定地點(已知經緯度),那麼我們需要查詢的就是使用者當前的位置,所以首先要定位使用者當前位置。
/** * 開啟定位,回撥介面為MyLocationListener類 /介面 */ private void StartLocation() { LocationClientOption option = new LocationClientOption(); option.setLocationMode(LocationMode.Hight_Accuracy);//設定定位模式 option.setCoorType("gcj02");//返回的定位結果是百度經緯度 option.setScanSpan(1000);//設定發起定位請求的間隔時間為1000ms option.setIsNeedAddress(true); //是否需要返回地址 mLocationClient.setLocOption(option); mLocationClient.start();//發起定位請求 }
接著看回調介面:
/** * 定位回撥監聽 * */ public class MyLocationListener implements BDLocationListener { @Override public void onReceiveLocation(BDLocation location) { //回撥返回物件物件裡包含多個屬性,這裡我們只需要經緯度 userLatLng = new LatLng(location.getLatitude(), location.getLongitude()); //這句程式碼可以忽略,我不知道定位可以拿到具體的地址,所以使用了 詳細地址與經緯度轉化的介面 //其實location.getAddrStr();就可以拿到地址 if(userLatLng != null){ mGeoCoder.reverseGeoCode(new ReverseGeoCodeOption() .location(userLatLng)); } mLocationClient.stop(); } }
接著看將經緯度轉化為具體詳細地址的回撥介面:
@Override
public void onGetReverseGeoCodeResult(ReverseGeoCodeResult result) {
if (result == null || result.error != SearchResult.ERRORNO.NO_ERROR) {
Host.showToast(R.string.map_result_error);
return;
}
baiduMap.addOverlay(new MarkerOptions().position(result.getLocation())
.icon(BitmapDescriptorFactory
.fromResource(R.drawable.baidu_map_marka)));
baiduMap.setMapStatus(MapStatusUpdateFactory.newLatLng(result
.getLocation()));
mPosition = result.getAddress().toString();//以上程式碼忽略,這裡的mPosition就是具體的地址
PlanNode stNode = null, enNode = null; //宣告兩個節點,stNote 起始節點, enNode目的地節點
if(!IsExchanged) //這裡的if else 可忽略,是為了實現目標地址與當前地址互換效果而做的
{
myAddress.setText(mPosition);
stNode = PlanNode.withLocation(userLatLng);//將經緯度物件傳入
enNode = PlanNode.withLocation(latLng);
}else
{
targetAddress.setText(mPosition);
enNode = PlanNode.withLocation(userLatLng);
stNode = PlanNode.withLocation(latLng);
}
StartRouteSearch(stNode, enNode); //開始搜尋
}
/**
* 發起路線規劃請求,獲取路線
* 回撥介面為onGetTransitRouteResult/onGetWalkingRouteResult/onGetDrivingRouteResult
* @param stNode
* @param enNode
*/
private void StartRouteSearch(PlanNode stNode, PlanNode enNode) {
route = null;
baiduMap.clear(); //每次重新搜尋都清空地圖上的所有標記以及路線
if (searchType == SearchType.BUS) {
mSearch.drivingSearch((new DrivingRoutePlanOption()).from(stNode).to(enNode)); //搜尋駕車路線
} else if (searchType == SearchType.CAR) {
mSearch.transitSearch((new TransitRoutePlanOption()).from(stNode).city("無錫").to(enNode));//搜尋公交路線
} else if (searchType == SearchType.WALK) {
mSearch.walkingSearch((new WalkingRoutePlanOption()).from(stNode).to(enNode));//搜尋行走路線
}
}
這裡的三鍾搜尋方式對應三個不同的回撥介面,分別是:
@Override
public void onGetDrivingRouteResult(DrivingRouteResult dRouteResult) {
if (dRouteResult == null || dRouteResult.error != SearchResult.ERRORNO.NO_ERROR) {
Host.showToast(R.string.map_result_error);
}
if (dRouteResult.error == SearchResult.ERRORNO.AMBIGUOUS_ROURE_ADDR) {
// 起終點或途經點地址有岐義,通過以下介面獲取建議查詢資訊
// result.getSuggestAddrInfo()
return;
}
if (dRouteResult.error == SearchResult.ERRORNO.NO_ERROR) {
// nodeIndex = -1;
route = dRouteResult.getRouteLines().get(0); //獲取路線
DrivingRouteOverlay overlay = new DrivingRouteOverlay(baiduMap);
routeOverlay = overlay;
baiduMap.setOnMarkerClickListener(overlay);
overlay.setData(dRouteResult.getRouteLines().get(0));//overLay 為在地圖上的路徑 ,這裡為它設定資料
overlay.addToMap(); //新增到地圖
overlay.zoomToSpan();
}
}
@Override
public void onGetWalkingRouteResult(WalkingRouteResult result) {
if (result == null || result.error != SearchResult.ERRORNO.NO_ERROR) {
Host.showToast(R.string.map_result_error);
}
if (result.error == SearchResult.ERRORNO.AMBIGUOUS_ROURE_ADDR) {
// 起終點或途經點地址有岐義,通過以下介面獲取建議查詢資訊
// result.getSuggestAddrInfo()
return;
}
if (result.error == SearchResult.ERRORNO.NO_ERROR) { //同上
route = result.getRouteLines().get(0);
WalkingRouteOverlay overlay = new WalkingRouteOverlay(baiduMap);
baiduMap.setOnMarkerClickListener(overlay);
routeOverlay = overlay;
overlay.setData(result.getRouteLines().get(0));
overlay.addToMap();
overlay.zoomToSpan();
}
}
@Override
public void onGetTransitRouteResult(TransitRouteResult result) {
if (result == null || result.error != SearchResult.ERRORNO.NO_ERROR) {
Host.showToast(R.string.map_result_error);
}
if (result.error == SearchResult.ERRORNO.AMBIGUOUS_ROURE_ADDR) {
// 起終點或途經點地址有岐義,通過以下介面獲取建議查詢資訊
// result.getSuggestAddrInfo()
return;
}
if (result.error == SearchResult.ERRORNO.NO_ERROR) { //同上
route = result.getRouteLines().get(0);
TransitRouteOverlay overlay = new TransitRouteOverlay(baiduMap);
baiduMap.setOnMarkerClickListener(overlay);
routeOverlay = overlay;
overlay.setData(result.getRouteLines().get(0));
overlay.addToMap();
overlay.zoomToSpan();
}
}
這樣一個基本的百度地圖路徑搜尋就完成了.