1. 程式人生 > >百度地圖開發(三)之地圖控制 + 定位

百度地圖開發(三)之地圖控制 + 定位

    接下來,這篇blog主要說一些關於地圖控制方面的內容和定位功能。

    百度地圖提供的關於地圖的操作主要有:單擊、雙擊、長按、縮放、旋轉、俯視等。

地圖控制

    我們現在已經知道,想要顯示一個地圖,只需要在xml檔案中新增一個MapView控制元件即可,但是想要對其進行一些控制,就需要通過這個控制元件返回一個BaiduMap物件。

從API中先看一下MapView的方法:


    對於MapView這個類,官方解釋是一個顯示地圖的檢視,負責從伺服器端獲取地圖資料,並且會捕捉到螢幕觸控手勢事件。使用這個類必須按照它的生命週期進行操作,從上圖可以看到,它包括一些類似於activity生命週期的方法:onResume()、onPause()、onDestory()。所以我們需要在activity的各個生命週期中,把MapView的各個生命週期函式新增進去。

    在使用地圖控制元件之前必須呼叫SDKInitializer.initialize(Context)函式用以提供全域性Context資訊。

    預設情況下,地圖顯示的時候會帶著原生的縮放控制元件:。還有比例尺控制元件:

通過showZoomControls(boolean show)showScaleControl(boolean show)這兩個方法可以設定顯示或者不顯示兩個控制元件。還可以通過設定setxxxPosition(Point p)方法來設定控制元件的位置。

mapView.showZoomControls(false);// 不顯示預設的縮放控制元件
mapView.showScaleControl(false);// 不顯示預設比例尺控制元件
    要想實現地圖的一些控制,就需要使用到BaiduMap,這個類是專門用來操作地圖控制元件的。



    上面的四個介面就是用來對地圖新增相應的事件的。我們主要看一下下面的兩個方法,它們都是以動畫的方式更新地圖狀態。不同的是一個可以指定時長,另一個有預設的動畫耗時。

    引數MapStatusUpdate描述的是地圖狀態將要發生的變化。也就是說,要想改變地圖的某些狀態,需要構造出一個MapStatusUpdate物件,然後使用animateMapStatus()方法來更新地圖狀態。但是並沒有在API中找到它的相關的構造方法。但是在com.baidu.mapapi.map包下面找到了對應的"工廠類"


    開啟MapStatusUpdateFactory可以看到很多靜態的方法:


    通過這些靜態的方法能夠構造出各種型別的MapStatusUpdate物件。

    zoomIn()和zoomOut()分別是放大和縮小地圖,分別是在當前基礎上增加或較少1個級別。zoomTo()可以自己設定某一個縮放級別。百度地圖將地圖的級別定義為【3~19】。

放大:

msu = msuFactory.zoomIn();
bdMap.animateMapStatus(msu);

縮小:

msu = msuFactory.zoomOut();
bdMap.animateMapStatus(msu);

設定地圖中心點:

msu = msuFactory.newLatLng(arg0);
bdMap.animateMapStatus(msu);
    其他的方法就不一一敘述了。
    關於地圖控制狀態的還有兩個類:MapStatusMapStatus.Builder。Builder是MapStatus的一個內部類,用於構造它,我們在API中可以看到MapStatus中是沒有建構函式的。

    使用這兩個類可以對地圖進行旋轉、俯視、設定中心點、設定縮放級別等操作。通過這些方法構造出MapStatus方法之後,怎麼讓BaiduMap呼叫它呢?

    查閱BaiduMap的所有方法之後也沒有找到引數是MapStatus的方法。那麼,猜想可能是通過把MapStatus轉換成一個其他的物件,然後在由BaiduMap呼叫。而BaiduMap只有animateMapStatus()方法來更新地圖狀態。所以很定是MapStatus--->MapStatusUpdate。在MSU的工廠類中有這樣一個方法:newMapStatus(MapStatus mapStatus)。OK,通過這個方法,可以把構造的MapStatus物件轉成MapStatusUpdate,然後在通過animateMapStatus()呼叫就行了。

旋轉:

mapStatus = new MapStatus.Builder(bdMap.getMapStatus()).rotate(rotateAngle += 30).build();
msu = msuFactory.newMapStatus(mapStatus);
bdMap.animateMapStatus(msu);

俯視(-45°~0):

mapStatus = new MapStatus.Builder(bdMap.getMapStatus()).overlook(overlookAngle -= 10).build();
msu = msuFactory.newMapStatus(mapStatus);
bdMap.animateMapStatus(msu);
    這裡,lz有一個疑問:MapStaus.Builder中有一個設定地圖中心點的方法:

,在MapStatusUpdateFactory中也有一個設定中心點的方法:。連個都是設定中心點,不知道區別是什麼?希望知道的給我留個言,告知一下!!謝謝!~~
截圖:

    在BaiduMap中有一個截圖的回撥介面和一個截圖的請求方法:



很明顯,呼叫這個截圖請求方法,引數是上面的回撥介面。在回撥介面中只有一個方法:onSnapshotReady(Bitmap snapshot)。我們得到這個bitmap之後,就可以生成圖片儲存起來了。

    有Bitmap轉成圖片就需要用到Bitmap.compress()方法:

bdMap.snapshot(new SnapshotReadyCallback() {
		@Override
		public void onSnapshotReady(Bitmap bitmap) {
			File file = new File("/mnt/sdcard/test.png");
			FileOutputStream out;
			try {
				out = new FileOutputStream(file);
				if (bitmap.compress(
						Bitmap.CompressFormat.PNG, 100, out)) {
					out.flush();
					out.close();
				}
				Toast.makeText(MapControllActivity.this,
						"螢幕截圖成功,圖片存在: " + file.toString(),
						Toast.LENGTH_SHORT).show();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	});

定位

    LZ採用的是百度最新版本5.0的SDK,該版本支援全球定位。

    開發定位功能一般都是按照以下步驟:

1. 匯入庫檔案。

    下載下來lib壓縮包之後,會看到很多資料夾(對應很多架構),官方建議全部拷貝到lib下,這樣程式相容性大大提升,不要忘了把locSDK_5.0.jar拷貝到lib下。
2. 新增定位service

<service
        android:name="com.baidu.location.f"
        android:enabled="true"
        android:process=":remote" >
</service>
3. 新增許可權
<!-- 這個許可權用於進行網路定位 -->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" >
    </uses-permission>
    <!-- 這個許可權用於訪問GPS定位 -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" >
    </uses-permission>
    <!-- 用於訪問wifi網路資訊,wifi資訊會用於進行網路定位 -->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" >
    </uses-permission>
    <!-- 獲取運營商資訊,用於支援提供運營商資訊相關的介面 -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" >
    </uses-permission>
    <!-- 這個許可權用於獲取wifi的獲取許可權,wifi資訊會用來進行網路定位 -->
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" >
    </uses-permission>
    <!-- 用於讀取手機當前的狀態 -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE" >
    </uses-permission>
    <!-- 寫入擴充套件儲存,向擴充套件卡寫入資料,用於寫入離線定位資料 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" >
    </uses-permission>
    <!-- 訪問網路,網路定位需要上網 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <!-- SD卡讀取許可權,使用者寫入離線定位資料 -->
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" >
    </uses-permission>
    <!-- 允許應用讀取低級別的系統日誌檔案 -->
    <uses-permission android:name="android.permission.READ_LOGS" >
    </uses-permission>
4. 編寫定位程式
    這一步才是重點。百度地圖可以使用GPS和網路定位(WIFI和基站)進行定位。基本定位功能還支援定位結果的反地理編碼功能,離線定位,位置提醒功能和地理圍欄功能。

    主要會用到LocationClient、BDLocationListener、BDNotifyListener、LocationClientOption等類。
    (1)初始化LocationClient類:

    LocationClient類是定位SDK的核心類,必須在主執行緒中宣告。需要傳入一個Context型別的引數,推薦使用getApplicationContext()來獲取全域性程序有效的context。

    主要會用到該類中的以下幾個方法:






   (2)設定定位引數:

    主要的引數有:定位模式、返回座標型別、是否開啟GPS等。

定位模式分為三種:

1. 高精度定位模式:同時使用網路定位和GPS定位,優先返回最高精度的定位結果。

2. 低功耗定位模式:不使用GPS,只使用網路定位(WiFi和基站)。

3. 僅用裝置定位模式: 不適用網路定位,只使用GPS進行定位。但是此模式下不支援室內環境的定位。


    在API中主要關注“setxxx”型別的函式。主要用到紅色框標註的方法。

LocationClientOption locOption = new LocationClientOption();
		locOption.setLocationMode(LocationMode.Hight_Accuracy);// 設定定位模式
		locOption.setCoorType("bd09ll");// 設定定位結果型別
		locOption.setScanSpan(5000);// 設定發起定位請求的間隔時間,ms
		locOption.setIsNeedAddress(true);// 返回的定位結果包含地址資訊
		locOption.setNeedDeviceDirect(true);// 設定返回結果包含手機的方向

		locationClient.setLocOption(locOption);
    座標型別分為三種:國測局經緯度座標系(gcj02),百度墨卡託座標系(bd09),百度經緯度座標系(bd09ll)。


    設定請求定位時間間隔:


    設定返回結果包含地址資訊:


    設定返回結果中包含手機方向:


    (3)設定定位監聽函式

locationClient.registerLocationListener(locationListener);
//
class MyLocationListener implements BDLocationListener {
		// 非同步返回的定位結果
		@Override
		public void onReceiveLocation(BDLocation location) {
    }
}
    百度官網說明有一些是不準確的。實現BDLocationListener介面的時候,在之前的版本是有兩個方法需要實現,新版本(5.0)的只有一個方法需要實現:onReceiveLocation()。BDLocation類封裝了定位SDK的定位結果,通過該可以獲取定位返回的結果、位置座標、精度半徑等資訊。



    定位成功與否,定位的錯誤碼都是通過getLocType()這個方法得到的,返回值是int型別。


    注意:只有在使用網路定位的情況下,才能獲取當前位置的反地理編碼。

} else if (locType == BDLocation.TypeNetWorkLocation) {
				addrStr = location.getAddrStr();// 獲取反地理編碼(文字描述的地址)
				Toast.makeText(LocationActivity.this, addrStr,
						Toast.LENGTH_SHORT).show();
			}
    (4)新增位置提醒監聽函式
notifyListener = new MyNotifyListener();
notifyListener.SetNotifyLocation(longitude, latitude, 3000, "bd09ll");//精度,維度,範圍,座標型別
locationClient.registerNotify(notifyListener);
/**
	 * 位置提醒監聽器
	 * @author ys
	 *
	 */
	class MyNotifyListener extends BDNotifyListener {
		@Override
		public void onNotify(BDLocation bdLocation, float distance) {
			super.onNotify(bdLocation, distance);
			mVibrator.vibrate(1000);//振動提醒已到設定位置附近
	    	Toast.makeText(LocationActivity.this, "震動提醒", Toast.LENGTH_SHORT).show();
		}
	}
    (5)開啟定位
    LocationClient的start()方法用來啟動定位SDK,requestLocation()方法用來請求一次定位,請求過程是非同步的。呼叫start()方法之後,會根據你設定的定位事件間隔來請求定位。

    (6)最後不要忘了在不用的時候登出定位監聽和位置提醒監聽,並且關閉地圖。

@Override
	protected void onDestroy() {
		super.onDestroy();
		mapview.onDestroy();
		locationClient.unRegisterLocationListener(locationListener);
		//取消位置提醒
		locationClient.removeNotifyEvent(notifyListener);
		locationClient.stop();
	}
    此時可以完成了一個基本的地圖定位功能和位置提醒。如果要顯示在地圖上,就想百度那樣出現一個點表示地圖的定位點,就需要用到MyLocationConfiguration(配置定點陣圖層顯示方式)MylocationData(定位資料)

    MyLocationData包含一個內部了Builder用於構建MyLocationData物件:

// 構造定位資料
			MyLocationData locData = new MyLocationData.Builder()
					.accuracy(radius)//
					.direction(direction)// 方向
					.latitude(latitude)//
					.longitude(longitude)//
					.build();
			// 設定定位資料
			bdMap.setMyLocationData(locData);
    通過定位的onReceiveLocation()方法可以得到定位的經緯度,然後可以通過animationMapStatus()方法把定位到的點移動到地圖中心。
LatLng ll = new LatLng(latitude, longitude);
			MapStatusUpdate msu = MapStatusUpdateFactory.newLatLng(ll);
			bdMap.animateMapStatus(msu);
    定點陣圖層的顯示方式有三種:普通、跟隨、羅盤,在MyLocationConfiguration.LocationMode這個內部類中定義為列舉常量。

    我們來看一下MyLocationConfiguration的建構函式:


    第一個引數就是圖層的顯示方式(LocationMode型別),第二個引數表示是否顯示方向資訊(booleab型別),第三個引數是(bitmapDescriptor型別,我們在前面的blog有過介紹了)。構造出這個物件之後,就可以呼叫BaiduMap的setMyLocationConfigeration()方法來設定定點陣圖層配置資訊了。


switch (currentMode) {
			case NORMAL:
				locateBtn.setText("跟隨");
				currentMode = MyLocationConfiguration.LocationMode.FOLLOWING;
				break;
			case FOLLOWING:
				locateBtn.setText("羅盤");
				currentMode = MyLocationConfiguration.LocationMode.COMPASS;
				break;
			case COMPASS:
				locateBtn.setText("普通");
				currentMode = MyLocationConfiguration.LocationMode.NORMAL;
				break;
			}
			bdMap.setMyLocationConfigeration(new MyLocationConfiguration(
					currentMode, true, currentMarker));

總結

    OK,本篇blog主要講解了地圖的控制(縮放、旋轉、俯視等)和定位功能,其中定位方面比較複雜一些。 lz也是自己一個人研究,未免有遺漏或者錯誤之處,希望大家指出,謝謝!