1. 程式人生 > >百度地圖API製作類似 百度地圖的路線導航介面並實現簡單的路線規劃功能

百度地圖API製作類似 百度地圖的路線導航介面並實現簡單的路線規劃功能

之前我們講了怎麼在百度地圖上設定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();
		}
	}

這樣一個基本的百度地圖路徑搜尋就完成了.