1. 程式人生 > 實用技巧 >百度地圖SDK2.0覆蓋物新增

百度地圖SDK2.0覆蓋物新增

>>> hot3.png

闡述一個概念,地圖覆蓋物:所有疊加或覆蓋到地圖的內容,我們統稱為地圖覆蓋物。如標註、向量圖形元素(包括:折線和多邊形和圓)、定點陣圖標等。覆蓋物擁有自己的地理座標,當您拖動或縮放地圖時,它們會相應的移動。

要實現的需求:假如我們知道北京天安門(建築物)的GPS緯度經度值:39.915,116.404,想要把它在百度地圖上標註出來。

實現上述需求的步驟:

一、準備工作:

1、建立android工程,並匯入百度地圖需要用到的jar包和so檔案。

2、在AndroidManifest檔案中新增使用百度地圖SDK所需的許可權及螢幕配置。

3、在佈局檔案layout中新增顯示百度地圖的MapView。

4、在繼承了Activity類的子類中:

a. 建立並初始化地圖引擎管理物件;

b. 通過元件ID獲取代表地圖顯示View的MapView物件,並設定相應屬性。

(比如:啟用內建的縮放控制元件、設定允許的地圖縮放級別等)

c. 重寫Activity的生命週期回撥方法onResume()、onPause()和onDestroy(),管理地圖引擎管理類物件和顯示物件生命週期。

5、詳細的請閱讀上一篇:Android 百度地圖SDK (v2.0.0)初探

二、在地圖上標註出北京天安門:

1、想要在地圖上標註一個建築物,總得有一個標識吧?

獲取在地圖上標識建築物的圖示物件:


[mw_shl_code=java,true] // 獲取用於在地圖上標註一個地理座標點的圖示
Drawable drawable = this.getResources().getDrawable(R.drawable.icon_marka);[/mw_shl_code]

2、在基礎圖上新增覆蓋物(新增圖層)

a. 編寫覆蓋物類,自己定義一個類,繼承自ItemizedOverlay<OverlayItem>類,需要重寫父類的建構函式、createItem(int index)和size()方法。

注:從2.0.0開始,SDK不支援直接繼承Overlay , 使用者可通過繼承ItemizedOverlay來新增覆蓋物。

b. 在自定義的覆蓋物類(繼承自ItemizedOverlay<OverlayItem>)中, 宣告一個用於存放覆蓋物的集合:

[mw_shl_code=java,true]/**覆蓋物列表集合*/
private ArrayList<OverlayItem> mOverlayList = new ArrayList<OverlayItem>();[/mw_shl_code]

宣告double型別的變數儲存北京天安門的緯度、經度值:
[mw_shl_code=java,true] // 宣告double型別的變數儲存北京天安門的緯度、經度值
private double mLat1 = 39.915; // point1緯度

private double mLon1 = 116.404; // point1經度[/mw_shl_code]
c. 在建構函式中,將GPS緯度經度值轉換成以微度的整數形式儲存的地理座標點
[mw_shl_code=java,true]/*注:GeoPoint物件構造方法的引數列表:第一個是引數表示緯度,第二個是經度
(我們平時都是經緯度這麼叫的,想著應該是經度在前的,呵呵。)
在網上查了下,GPS的值官方給的就是緯度經度,也就是說緯度是在前的,以前一直沒太注意。*/
GeoPoint geoPoint1 = new GeoPoint((int) (mLat1 * 1E6), (int) (mLon1 * 1E6));[/mw_shl_code]
構造OverlayItem物件並新增到mOverlayList集合裡
[mw_shl_code=java,true]mOverlayList.add(new OverlayItem(geoPoint1, "point1", "point1"));[/mw_shl_code]
必須呼叫的方法:
[mw_shl_code=java,true] /*
* 官方的解釋:在一個新ItemizedOverlay上執行所有操作的工具方法。
* 沒搞明白啥意思,但是必須的呼叫這個方法,否則程式執行報錯*/
populate();[/mw_shl_code]
d. 返回的是從指定List集合中,取出的一個OverlayItem物件。
[mw_shl_code=java,true]/*
* 返回的是從指定List集合中,取出的一個OverlayItem物件。
* mOverlayList集合裡一旦有了資料,在呼叫其之前,
* 一定的在MyOverlayItem的建構函式裡呼叫這個方法populate();
*/
@Override
protected OverlayItem createItem(int index) {
return mOverlayList.get(index);
}[/mw_shl_code]
e. 獲取當前覆蓋物列表的大小
[mw_shl_code=java,true]@Override
public int size() {
return mOverlayList.size();
}[/mw_shl_code]
自定義的覆蓋物類的完整程式碼:
[mw_shl_code=java,true] /**
* 包含了一個覆蓋物列表的覆蓋物類
* @author android_ls
*/
final class MyOverlayItem extends ItemizedOverlay<OverlayItem> {

/**覆蓋物列表集合*/
private ArrayList<OverlayItem> mOverlayList = new ArrayList<OverlayItem>();

// 宣告double型別的變數儲存北京天安門的緯度、經度值
private double mLat1 = 39.915; // point1緯度

private double mLon1 = 116.404; // point1經度

// 傳進來的Drawable物件用於在地圖上標註一個地理座標點
public MyOverlayItem(Drawable drawable) {
super(drawable);

// 將GPS緯度經度值轉換成以微度的整數形式儲存的地理座標點

/*注:GeoPoint物件構造方法的引數列表:第一個是引數表示緯度,第二個是經度
(我們平時都是經緯度這麼叫的,想著應該是經度在前的,呵呵。)
在網上查了下,GPS的值官方給的就是緯度經度,也就是說緯度是在前的,以前一直沒太注意。*/
GeoPoint geoPoint1 = new GeoPoint((int) (mLat1 * 1E6), (int) (mLon1 * 1E6));

// 構造OverlayItem物件並新增到mOverlayList集合裡
mOverlayList.add(new OverlayItem(geoPoint1, "point1", "point1"));

/*
* 官方的解釋:在一個新ItemizedOverlay上執行所有操作的工具方法。
* 沒搞明白啥意思,但是必須的呼叫這個方法,否則程式執行報錯*/
populate();
}

/*
* 返回的是從指定List集合中,取出的一個OverlayItem物件。
* mOverlayList集合裡一旦有了資料,在呼叫其之前,
* 一定的在MyOverlayItem的建構函式裡呼叫這個方法populate();
*/
@Override
protected OverlayItem createItem(int index) {
return mOverlayList.get(index);
}

@Override
public int size() {
return mOverlayList.size();
}

}[/mw_shl_code]
建立覆蓋物(MyOverlayItem)物件並新增到覆蓋物列表中:
[mw_shl_code=java,true]mMapView.getOverlays().add(new MyOverlayItem(drawable));[/mw_shl_code]
3、重新整理地圖
[mw_shl_code=java,true]mMapView.refresh();[/mw_shl_code]

執行效果圖如下:

23101444_b9mV.jpg



完整程式碼:

[mw_shl_code=java,true]package com.android.baidu.map;

import java.util.ArrayList;

import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.widget.Toast;

import com.baidu.mapapi.BMapManager;
import com.baidu.mapapi.MKGeneralListener;
import com.baidu.mapapi.map.ItemizedOverlay;
import com.baidu.mapapi.map.MKEvent;
import com.baidu.mapapi.map.MapController;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.OverlayItem;
import com.baidu.platform.comapi.basestruct.GeoPoint;

/**
* 在地圖上標註已知GPS緯度經度值的建築物
* 場景:假如我們知道北京天安門(建築物)的GPS緯度經度值:39.915,116.404,想要把它在地圖上標註出來。
* @author android_ls
*
*/
public class BaiduMapOverlayActivity extends Activity {

/**地圖引擎管理類*/
private BMapManager mBMapManager = null;

/**顯示地圖的View*/
private MapView mMapView = null;

/**
* 經研究發現在申請KEY時:應用名稱一定要寫成my_app_應用名(也就是說"my_app_"是必須要有的)。
* 百度地圖SDK提供的服務是免費的,介面無使用次數限制。您需先申請金鑰(key),才可使用該套SDK。
* */
public static final String BAIDU_MAP_KEY = "07418AEC69BAAB7104C6230A6120C580DFFAEEBB";

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// 注意:請在呼叫setContentView前初始化BMapManager物件,否則會報錯
mBMapManager = new BMapManager(this.getApplicationContext());
mBMapManager.init(BAIDU_MAP_KEY, new MKGeneralListener() {

@Override
public void onGetNetworkState(int iError) {
if (iError == MKEvent.ERROR_NETWORK_CONNECT) {
Toast.makeText(BaiduMapOverlayActivity.this.getApplicationContext(),
"您的網路出錯啦!",
Toast.LENGTH_LONG).show();
}
}

@Override
public void onGetPermissionState(int iError) {
if (iError == MKEvent.ERROR_PERMISSION_DENIED) {
// 授權Key錯誤:
Toast.makeText(BaiduMapOverlayActivity.this.getApplicationContext(),
"請在 DemoApplication.java檔案輸入正確的授權Key!",
Toast.LENGTH_LONG).show();
}
}
});

setContentView(R.layout.main);

mMapView = (MapView) this.findViewById(R.id.bmapsView);
// 設定啟用內建的縮放控制元件
mMapView.setBuiltInZoomControls(true);

// 獲取地圖控制器,可以用它控制平移和縮放
MapController mMapController = mMapView.getController();
// 設定地圖的縮放級別。 這個值的取值範圍是[3,18]。
mMapController.setZoom(13);

// 獲取用於在地圖上標註一個地理座標點的圖示
Drawable drawable = this.getResources().getDrawable(R.drawable.icon_marka);

// 建立覆蓋物(MyOverlayItem)物件並新增到覆蓋物列表中
mMapView.getOverlays().add(new MyOverlayItem(drawable));

// 重新整理地圖
mMapView.refresh();

}

/**
* 包含了一個覆蓋物列表的覆蓋物類
* @author android_ls
*/
final class MyOverlayItem extends ItemizedOverlay<OverlayItem> {

/**覆蓋物列表集合*/
private ArrayList<OverlayItem> mOverlayList = new ArrayList<OverlayItem>();

// 宣告double型別的變數儲存北京天安門的緯度、經度值
private double mLat1 = 39.915; // point1緯度

private double mLon1 = 116.404; // point1經度

// 傳進來的Drawable物件用於在地圖上標註一個地理座標點
public MyOverlayItem(Drawable drawable) {
super(drawable);

// 將GPS緯度經度值轉換成以微度的整數形式儲存的地理座標點

/* 注:GeoPoint物件構造方法的引數列表:第一個是引數表示緯度,
* 第二個是經度(我們平時都是經緯度這麼叫的,想著應該是經度在前的,呵呵。)
* 在網上查了下,GPS的值官方給的就是緯度經度,也就是說緯度是在前的,以前一直沒太注意。*/
GeoPoint geoPoint1 = new GeoPoint(
(int) (mLat1 * 1E6),
(int) (mLon1 * 1E6));

// 構造OverlayItem物件並新增到mOverlayList集合裡
mOverlayList.add(new OverlayItem(geoPoint1, "point1", "point1"));

/*
* 官方的解釋:在一個新ItemizedOverlay上執行所有操作的工具方法。
* 沒搞明白啥意思,但是必須的呼叫這個方法,否則程式執行報錯*/
populate();
}

/*
* 返回的是從指定List集合中,取出的一個OverlayItem物件。
* mOverlayList集合裡一旦有了資料,在呼叫其之前,
* 一定的在MyOverlayItem的建構函式裡呼叫這個方法populate();
*/
@Override
protected OverlayItem createItem(int index) {
return mOverlayList.get(index);
}

@Override
public int size() {
return mOverlayList.size();
}

}

// 重寫以下方法,管理API
@Override
protected void onResume() {
mMapView.onResume();
if (mBMapManager != null) {
mBMapManager.start();
}
super.onResume();
}

@Override
protected void onPause() {
mMapView.onPause();
if (mBMapManager != null) {
mBMapManager.stop();
}
super.onPause();
}

@Override
protected void onDestroy() {
mMapView.destroy();
if (mBMapManager != null) {
mBMapManager.destroy();
mBMapManager = null;
}
super.onDestroy();
}
}[/mw_shl_code]

三、在地圖上標註出北京天安門附近的幾個點:

從2.0.0開始,SDK不支援直接繼承Overlay 。 在地圖上顯示一個或一組覆蓋物,都可以通過繼承ItemizedOverlay來新增覆蓋物。

在上面講解的基礎上,修改覆蓋物類的部分程式碼就可以了。直接上程式碼:


[mw_shl_code=java,true]class MyOverlayItem extends ItemizedOverlay<OverlayItem> {

/**覆蓋物列表集合*/
private ArrayList<OverlayItem> mOverlayList = new ArrayList<OverlayItem>();

// 場景:假如我們有一組建築物的GPS經緯度值,想要把這些建築物在地圖上標註出來。

private double mLat1 = 39.90923; // point1緯度

private double mLon1 = 116.397428; // point1經度

private double mLat2 = 39.9022;// point2緯度

private double mLon2 = 116.3922; // point2經度

private double mLat3 = 39.917723; // point3緯度

private double mLon3 = 116.3722; // point3緯度

private double mLat4 = 39.915; // point4緯度

private double mLon4 = 116.404; // point4經度

// 傳進來的Drawable物件用於在地圖上標註一個地理座標點
public MyOverlayItem(Drawable drawable) {
super(drawable);

// 將GPS緯度經度值轉換成以微度的整數形式儲存的地理座標點

/*注:GeoPoint物件構造方法的引數列表:第一個是引數表示緯度,第二個是經度
(我們平時都是經緯度這麼叫的,想著應該是經度在前的,呵呵。)
在網上查了下,GPS的值官方給的就是緯度經度,也就是說緯度是在前的,以前一直沒太注意。*/
GeoPoint geoPoint1 = new GeoPoint((int) (mLat1 * 1E6), (int) (mLon1 * 1E6));
GeoPoint geoPoint2 = new GeoPoint((int) (mLat2 * 1E6), (int) (mLon2 * 1E6));
GeoPoint geoPoint3 = new GeoPoint((int) (mLat3 * 1E6), (int) (mLon3 * 1E6));
GeoPoint geoPoint4 = new GeoPoint((int) (mLat4 * 1E6), (int) (mLon4 * 1E6));

// 構造OverlayItem物件並新增到mOverlayList集合裡
mOverlayList.add(new OverlayItem(geoPoint1, "point1", "point1"));
mOverlayList.add(new OverlayItem(geoPoint2, "point2", "point2"));
mOverlayList.add(new OverlayItem(geoPoint3, "point3", "point3"));
mOverlayList.add(new OverlayItem(geoPoint4, "point4", "point4"));

// 必須的呼叫這個方法,否則程式執行報錯
populate();
}

/*
* 返回的是從指定List集合中,取出的一個OverlayItem物件。
* mOverlayList集合裡一旦有了資料,在呼叫其之前,
* 一定的在MyOverlayItem的建構函式裡呼叫這個方法populate();
*/
@Override
protected OverlayItem createItem(int index) {
return mOverlayList.get(index);
}

@Override
public int size() {
return mOverlayList.size();
}

}[/mw_shl_code]

對程式碼進行優化:

GPSPonit 實體類:


[mw_shl_code=java,true]package com.android.baidu.map.entity;

/**
* 類名: Ponit.java
* 功能描述:存放GPS緯度、經度值
* @author android_ls
* 建立日期: 2013-2-10 下午07:43:47
* @version V1.0
*/
public class GPSPonit {

private double mLat; // 緯度

private double mLon; // 經度

public double getmLat() {
return mLat;
}

public void setmLat(double mLat) {
this.mLat = mLat;
}

public double getmLon() {
return mLon;
}

public void setmLon(double mLon) {
this.mLon = mLon;
}

public GPSPonit(double mLat, double mLon) {
this.mLat = mLat;
this.mLon = mLon;
}

public GPSPonit() {
}

@Override
public String toString() {
return "Ponit [mLat=" + mLat + ", mLon=" + mLon + "]";
}

}[/mw_shl_code]
優化後的Activity類:
[mw_shl_code=java,true]package com.android.baidu.map;

import java.util.ArrayList;

import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.widget.Toast;

import com.android.baidu.map.entity.GPSPonit;
import com.baidu.mapapi.BMapManager;
import com.baidu.mapapi.MKGeneralListener;
import com.baidu.mapapi.map.ItemizedOverlay;
import com.baidu.mapapi.map.MKEvent;
import com.baidu.mapapi.map.MapController;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.OverlayItem;
import com.baidu.platform.comapi.basestruct.GeoPoint;

/**
* 在地圖上標註已知GPS緯度經度值的一組建築物
* @author android_ls
*
*/
public class BaiduMapOverlayItemsActivity extends Activity {

/**地圖引擎管理類*/
private BMapManager mBMapManager = null;

/**顯示地圖的View*/
private MapView mMapView = null;

/**
* 經研究發現在申請KEY時:應用名稱一定要寫成my_app_應用名(也就是說"my_app_"是必須要有的)。
* 百度地圖SDK提供的服務是免費的,介面無使用次數限制。您需先申請金鑰(key),才可使用該套SDK。
* */
public static final String BAIDU_MAP_KEY = "07418AEC69BAAB7104C6230A6120C580DFFAEEBB";

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// 注意:請在呼叫setContentView前初始化BMapManager物件,否則會報錯
mBMapManager = new BMapManager(this.getApplicationContext());
mBMapManager.init(BAIDU_MAP_KEY, new MKGeneralListener() {

@Override
public void onGetNetworkState(int iError) {
if (iError == MKEvent.ERROR_NETWORK_CONNECT) {
Toast.makeText(BaiduMapOverlayItemsActivity.this.getApplicationContext(),
"您的網路出錯啦!",
Toast.LENGTH_LONG).show();
}
}

@Override
public void onGetPermissionState(int iError) {
if (iError == MKEvent.ERROR_PERMISSION_DENIED) {
// 授權Key錯誤:
Toast.makeText(BaiduMapOverlayItemsActivity.this.getApplicationContext(),
"請在 DemoApplication.java檔案輸入正確的授權Key!",
Toast.LENGTH_LONG).show();
}
}
});

setContentView(R.layout.main);

mMapView = (MapView) this.findViewById(R.id.bmapsView);
// 設定啟用內建的縮放控制元件
mMapView.setBuiltInZoomControls(true);

// 獲取地圖控制器,可以用它控制平移和縮放
MapController mMapController = mMapView.getController();
// 設定地圖的縮放級別。 這個值的取值範圍是[3,18]。
mMapController.setZoom(13);

//TODO 構建一組資料
GPSPonit gp1 = new GPSPonit(39.90923, 116.397428);
GPSPonit gp2 = new GPSPonit(39.9022, 116.3922);
GPSPonit gp3 = new GPSPonit(39.917723, 116.3722);
GPSPonit gp4 = new GPSPonit(39.915, 116.404);

/**存放GPS緯度、經度值的陣列*/
GPSPonit[] mGPSPonit = new GPSPonit[4];
mGPSPonit[0] = gp1;
mGPSPonit[1] = gp2;
mGPSPonit[2] = gp3;
mGPSPonit[3] = gp4;

Drawable drawable = this.getResources().getDrawable(R.drawable.icon_marka);
// 建立覆蓋物(MyOverlayItem)物件並新增到覆蓋物列表中
mMapView.getOverlays().add(new MyOverlayItem(drawable, mGPSPonit));

// 重新整理地圖
mMapView.refresh();
}

final class MyOverlayItem extends ItemizedOverlay<OverlayItem> {

/**覆蓋物列表集合*/
private ArrayList<OverlayItem> mOverlayList = new ArrayList<OverlayItem>();

// 場景:假如我們有一組建築物的GPS經緯度值,想要把這些建築物在地圖上標註出來。

// 傳進來的Drawable物件用於在地圖上標註一個地理座標點
public MyOverlayItem(Drawable drawable, GPSPonit[] gPSPonit) {
super(drawable);

for(int i = 0; i < gPSPonit.length; i++){
GPSPonit gpp = gPSPonit;

GeoPoint geoPoint = new GeoPoint(
(int) (gpp.getmLat() * 1E6),
(int) (gpp.getmLon() * 1E6));

mOverlayList.add(new OverlayItem(geoPoint, "point"+i, "point1"+i));
}

// 必須的呼叫這個方法,否則程式執行報錯
populate();
}

/*
* 返回的是從指定List集合中,取出的一個OverlayItem物件。
* mOverlayList集合裡一旦有了資料,在呼叫其之前,
* 一定的在MyOverlayItem的建構函式裡呼叫這個方法populate();
*/
@Override
protected OverlayItem createItem(int index) {
return mOverlayList.get(index);
}

@Override
public int size() {
return mOverlayList.size();
}

}

// 重寫以下方法,管理API
@Override
protected void onResume() {
mMapView.onResume();
if (mBMapManager != null) {
mBMapManager.start();
}
super.onResume();
}

@Override
protected void onPause() {
mMapView.onPause();
if (mBMapManager != null) {
mBMapManager.stop();
}
super.onPause();
}

@Override
protected void onDestroy() {
mMapView.destroy();
if (mBMapManager != null) {
mBMapManager.destroy();
mBMapManager = null;
}
super.onDestroy();
}
}[/mw_shl_code]

執行效果圖如下:

23101444_F25y.jpg



轉載於:https://my.oschina.net/boonya/blog/317244