這是一個(gè)系列,但是我也不確定具體會(huì)更新多少期,最近很忙,主要還是效率的問(wèn)題,所以一些有效的東西還是會(huì)及時(shí)更新的,比如后續(xù)會(huì)出 - 分享SDK:sharesdk - 后端SDK:Bmob - 推送SDK:極光推送 - 短信SDK:驗(yàn)證碼實(shí)現(xiàn) - 等等...... 或者出一些裝ubuntu系統(tǒng)或者黑蘋果教程什么的,或者5.X之后的新玩法,主要還是困于時(shí)間方面缺少,或許這也是一種鍛煉吧,工作了挺久的了,越發(fā)覺(jué)得自己的JAVA基礎(chǔ)實(shí)在是爛的可以,想去買一本JAVA的書籍啃一啃,剛好年假也有15天,這都是后話了,我們言歸正傳,今天分析的是百度地圖的sdk怎么去使用,包括他的幾個(gè)類的詳細(xì)說(shuō)明,可能寫得快的話半個(gè)禮拜就寫完了就會(huì)加上高德地圖什么的,不過(guò)看現(xiàn)在公司項(xiàng)目的樣子,一天能寫一個(gè)小時(shí)就不錯(cuò)了 一.百度API 百度地圖API:http://developer.baidu.com/map/ 二.搭建地圖環(huán)境 1.申請(qǐng)百度地圖的key 2.下載對(duì)應(yīng)功能的sdk 3.新建一個(gè)工程導(dǎo)入sdk到lib里面 1.申請(qǐng)KEY 我們打開(kāi)百度API官網(wǎng)-開(kāi)發(fā)-Android SDK 然后選擇獲取密鑰 創(chuàng)建應(yīng)用 我們?cè)贗DE里創(chuàng)建一個(gè)工程--BaiDuMapDemo 然后依次填入所需要的信息 這里很多人對(duì)這個(gè)SHA1值很疑問(wèn),那我先科普一下這個(gè)是什么玩意吧 什么是SHA1? 安全哈希算法(Secure Hash Algorithm)主要適用于數(shù)字簽名標(biāo)準(zhǔn) (Digital Signature Standard DSS)里面定義的數(shù)字簽名算法(Digital Signature Algorithm DSA)。對(duì)于長(zhǎng)度小于2^64位的消息,SHA1會(huì)產(chǎn)生一個(gè)160位的消息摘要。當(dāng)接收到消息的時(shí)候,這個(gè)消息摘要可以用來(lái)驗(yàn)證數(shù)據(jù)的完整性。在傳輸?shù)倪^(guò)程中,數(shù)據(jù)很可能會(huì)發(fā)生變化,那么這時(shí)候就會(huì)產(chǎn)生不同的消息摘要。 SHA1有如下特性:不可以從消息摘要中復(fù)原信息;兩個(gè)不同的消息不會(huì)產(chǎn)生同樣的消息摘要。 那我們?cè)撊绾稳カ@取呢? Eclipse獲取方法 Android Studio獲取方法 借鑒博文:http://blog.csdn.net/kezhongke/article/details/42678077 好了,這里注意一下,這里我用com.lgl.baidumapdemo這個(gè)包名官方提示我敏感詞,所以我換了一個(gè),本質(zhì)上是沒(méi)有任何影響的,不用糾結(jié),當(dāng)我們提交之后,就可以獲取到key了 2.下載SDK 我想我不用多說(shuō)什么的,這里需要自定義下載,也就是說(shuō)你需要什么功能你就選擇什么功能,這里做demo的話全部下載了,這里也不提供下載了,你們可以自己去下載,我把地址給出來(lái)吧: SDK下載地址:http://developer.baidu.com/map/index.php?title=androidsdk/sdkandev-download 3.配置工程 首先我們把下載的sdk全部放在lib庫(kù)里面,有點(diǎn)多,畢竟百度地圖的功能還是可以的,不過(guò)會(huì)顯得很臃腫,建議需要什么功能就放哪個(gè)架包吧,下載的時(shí)候我相關(guān)的demo和文檔說(shuō)明的 Eclipse
Android Studio 第一步:在工程app/libs目錄下放入baidumapapi_vX_X_X.jar包,在src/main/目錄下新建jniLibs目錄,放入libBaiduMapSDK_vX_X_X_X.so如下圖所示,注意jar和so的前3位版本號(hào)必須一致,并且保證使用一次下載的文件夾中的兩個(gè)文件,不能不同功能組件的jar或so交叉使用。 第二步:導(dǎo)入jar包。菜單欄選擇File->Project Structor->Modules->Dependencies,點(diǎn)擊+號(hào),選擇File dependency,選擇jar包導(dǎo)入。 通過(guò)以上兩步操作后,您就可以正常使用百度地圖SDK為您提供的全部功能了。 三,HelloMap 1.權(quán)限 權(quán)限是必備的,而且說(shuō)明文檔里也十分詳細(xì)的說(shuō)明了 2.配置KEY 在application中添加開(kāi)發(fā)密鑰 android:name="com.baidu.lbsapi.API_KEY" android:value="開(kāi)發(fā)者 key" /> 3.布局 在布局中直接添加 android:id="@+id/bmapView" android:layout_width="fill_parent" android:layout_height="fill_parent" android:clickable="true" /> 4.初始化 在應(yīng)用程序創(chuàng)建時(shí)初始化 SDK引用的Context 全局變量: 記住,一定要再setContentView之前執(zhí)行 并且初始化mapview public class MainActivity extends Activity { private MapView mMapView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //在使用SDK各組件之前初始化context信息,傳入ApplicationContext //注意該方法要再setContentView方法之前實(shí)現(xiàn) SDKInitializer.initialize(getApplicationContext()); mMapView = (MapView) findViewById(R.id.bmapView); } } 5.地圖的生命周期 前期工作我們都準(zhǔn)備完成了,現(xiàn)在我們就把百度地圖的生命周期給添加上 @Override protected void onDestroy() { super.onDestroy(); // 在activity執(zhí)行onDestroy時(shí)執(zhí)行mMapView.onDestroy(),實(shí)現(xiàn)地圖生命周期管理 mMapView.onDestroy(); } @Override protected void onResume() { super.onResume(); // 在activity執(zhí)行onResume時(shí)執(zhí)行mMapView. onResume (),實(shí)現(xiàn)地圖生命周期管理 mMapView.onResume(); } @Override protected void onPause() { super.onPause(); // 在activity執(zhí)行onPause時(shí)執(zhí)行mMapView. onPause (),實(shí)現(xiàn)地圖生命周期管理 mMapView.onPause(); } 好了,準(zhǔn)備了這么久,現(xiàn)在我們可以見(jiàn)證奇跡的時(shí)刻了 好的,我們的初級(jí)教程到這里了,下面,就是一些高級(jí)的玩法了 四.地圖進(jìn)階——基本控制 1.核心類 //三大核心類 1.BMapManager//百度地圖管理工具 2.MapView //地圖控件——MapView的MKMapViewListener //控件的點(diǎn)擊事件 3.MapController //地圖控制,必須MapViewy已經(jīng)存在 //控制地圖平移,縮放,選擇等.. 2.授權(quán)驗(yàn)證 我們做這種類型的應(yīng)用,一般也就兩個(gè)交互,一個(gè)就是key的授權(quán),還有一個(gè)就是網(wǎng)絡(luò)的授權(quán)了,我們我們?cè)陂_(kāi)始實(shí)現(xiàn)地圖功能之前應(yīng)該先去判斷一下這兩個(gè)條件是否實(shí)現(xiàn)了 3.實(shí)現(xiàn)廣播機(jī)制 其實(shí)就是寫個(gè)小廣播,不需要很多代碼 //初始化一個(gè)廣播 private MyBroadcastReceiver receiver; class MyBroadcastReceiver extends BroadcastReceiver { //實(shí)現(xiàn)一個(gè)廣播 @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); // 網(wǎng)絡(luò)錯(cuò)誤 if (action.equals(SDKInitializer.SDK_BROADCAST_ACTION_STRING_NETWORK_ERROR)) { Toast.makeText(MainActivity.this, "無(wú)法連接網(wǎng)絡(luò)", Toast.LENGTH_SHORT).show(); // key效驗(yàn)失敗 } else if(action.equals(SDKInitializer.SDK_BROADTCAST_ACTION_STRING_PERMISSION_CHECK_ERROR)) { Toast.makeText(MainActivity.this, "百度地圖key效驗(yàn)失敗",Toast.LENGTH_SHORT).show(); } } } //在onCreate()方法中注冊(cè)廣播 receiver = new MyBroadcastReceiver(); IntentFilter filter = new IntentFilter(); // 網(wǎng)絡(luò)錯(cuò)誤 filter.addAction(SDKInitializer.SDK_BROADCAST_ACTION_STRING_NETWORK_ERROR); // 效驗(yàn)key失敗 filter.addAction(SDKInitializer.SDK_BROADTCAST_ACTION_STRING_PERMISSION_CHECK_ERROR); registerReceiver(receiver, filter); //注意要在onDestroy()方法中銷毀這個(gè)廣播 unregisterReceiver(receiver); 廣播寫好了,我們來(lái)說(shuō)一下這兩條廣播吧 邏輯就是當(dāng)進(jìn)入應(yīng)用的時(shí)候sdk會(huì)去驗(yàn)證這兩個(gè)條件,如果發(fā)現(xiàn)網(wǎng)絡(luò)錯(cuò)誤或者驗(yàn)證Key失敗就會(huì)發(fā)送一條廣播,廣播接收者接收到了這條廣播之后彈出一個(gè)Toast,當(dāng)然,你如果想人性化一點(diǎn)也可以彈一個(gè)Dialog,這里作為demo就不做這么復(fù)雜的東西了 //網(wǎng)絡(luò)錯(cuò)誤 SDKInitializer.SDK_BROADCAST_ACTION_STRING_NETWORK_ERROR //key效驗(yàn)失敗 SDKInitializer.SDK_BROADTCAST_ACTION_STRING_PERMISSION_CHECK_ERROR 3.設(shè)置地圖縮放級(jí)別 雖然地圖上是有按鈕可以進(jìn)行縮放的,但是再某些場(chǎng)景還是需要我們?nèi)斯たs放,但是再縮放之前,我們應(yīng)該先來(lái)了解一下縮放級(jí)別縮放級(jí)別在2.X是個(gè)分水嶺,在2.X之前的級(jí)別是(3-18),之后是(3-19),主要是有兩個(gè)區(qū)別 1.修改了文件格式,具體是啥也不需要懂,只要知道,比如深圳的地圖100M,2.x之后只要15M左右就行了 2.增加了3D效果,這要在18或者19的級(jí)別上才可以看到 我們先把BaiduMap給實(shí)現(xiàn)了 private BaiduMap mBaiduMap; //在onCreate()中 mBaiduMap = mMapView.getMap(); 然后我們寫一個(gè)方法讓onCreate()調(diào)用 private void init(){ //描述地圖將要發(fā)生的變化,使用工廠類MapStatusUpdateFactory創(chuàng)建,設(shè)置級(jí)別 //為18,進(jìn)去就是18了,默認(rèn)是12 MapStatusUpdate mapStatusUpdate = MapStatusUpdateFactory.zoomTo(18); mBaiduMap.setMapStatus(mapStatusUpdate); //是否顯示縮放按鈕 //mMapView.showZoomControls(false); } 4.設(shè)置中心點(diǎn)(定位的初級(jí)實(shí)現(xiàn)) 你有沒(méi)有發(fā)現(xiàn),我們一進(jìn)去地圖顯示的是北京天安門,其實(shí)這個(gè)就叫中心點(diǎn),我們可以更改這個(gè)中心點(diǎn) 同樣的,我們寫一個(gè)方法在onCreate()中調(diào)用 private void init(){ //經(jīng)緯度(緯度,經(jīng)度) 我們這里設(shè)置深圳世界之窗的位置 LatLng latlng = new LatLng(22.5422870000,113.9804440000); MapStatusUpdate mapStatusUpdate_circle = MapStatusUpdateFactory.newLatLng(latlng); mBaiduMap.setMapStatus(mapStatusUpdate_circle); } 截圖 現(xiàn)在一進(jìn)去中心點(diǎn)就會(huì)在世界之窗的坐標(biāo)點(diǎn)了,我們定位的實(shí)現(xiàn)不就是獲取到坐標(biāo)點(diǎn)然后顯示嘛!嘿嘿! 5.地圖控制器(旋轉(zhuǎn),移動(dòng),縮放) 模擬點(diǎn)擊 模擬器上運(yùn)行按12345鍵實(shí)現(xiàn),當(dāng)然,你寫B(tài)utton的點(diǎn)擊事件也可以 @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_1: //放大縮放級(jí)別,每次放大一個(gè)級(jí)別 MapStatusUpdate bigStatus = MapStatusUpdateFactory.zoomIn(); mBaiduMap.setMapStatus(bigStatus); break; case KeyEvent.KEYCODE_2: //縮小縮放級(jí)別,每次縮小一個(gè)級(jí)別 MapStatusUpdate smallStatus = MapStatusUpdateFactory.zoomOut(); mBaiduMap.setMapStatus(smallStatus); break; case KeyEvent.KEYCODE_3: //以屏幕中心點(diǎn)旋轉(zhuǎn) MapStatus mapStatus = mBaiduMap.getMapStatus(); //獲取當(dāng)前地圖的狀態(tài) float rotate = mapStatus.rotate; //獲取旋轉(zhuǎn)角度 Log.i("旋轉(zhuǎn)角度", "rotate"+rotate); //用獲取到的當(dāng)前角度+30就是每次都旋轉(zhuǎn)30° 范圍0-360° MapStatus rotates =new MapStatus.Builder().rotate(rotate+30).build(); //更新地圖的選擇 MapStatusUpdate rotateStatus = MapStatusUpdateFactory.newMapStatus(rotates); mBaiduMap.setMapStatus(rotateStatus); break; case KeyEvent.KEYCODE_4: //以立體方式旋轉(zhuǎn) MapStatus mapStatusOver = mBaiduMap.getMapStatus(); //獲取當(dāng)前地圖的狀態(tài) float overlook = mapStatusOver.overlook; //獲取旋轉(zhuǎn)角度 Log.i("旋轉(zhuǎn)角度", "overlook"+overlook); //弧角范圍:0-45° MapStatus overlooks =new MapStatus.Builder().overlook(overlook-5).build(); MapStatusUpdate overlookStatus = MapStatusUpdateFactory.newMapStatus(overlooks); mBaiduMap.setMapStatus(overlookStatus); break; case KeyEvent.KEYCODE_5: //移動(dòng) MapStatusUpdate moveStatus = MapStatusUpdateFactory.newLatLng(new LatLng(22.5422870000, 113.9804440000)); //帶動(dòng)畫更新?tīng)顟B(tài) 默認(rèn)300ms mBaiduMap.animateMapStatus(moveStatus); break; } 6.指南針 //顯示指南針 mBaiduMap.getUiSettings().setCompassEnabled(true); //顯示位置 7.地圖事件 不是很常用,地圖本身都是自帶點(diǎn)擊事件的 //設(shè)置地圖單擊監(jiān)聽(tīng) mBaiduMap.setOnMapClickListener(new OnMapClickListener() { @Override public boolean onMapPoiClick(MapPoi arg0) { // TODO Auto-generated method stub return false; } @Override public void onMapClick(LatLng arg0) { // TODO Auto-generated method stub } }); //覆蓋物點(diǎn)擊事件 mBaiduMap.setOnMarkerClickListener(new OnMarkerClickListener() { @Override public boolean onMarkerClick(Marker arg0) { // TODO Auto-generated method stub return false; } }); //設(shè)置地圖雙擊監(jiān)聽(tīng) mBaiduMap.setOnMapDoubleClickListener(new OnMapDoubleClickListener() { @Override public void onMapDoubleClick(LatLng arg0) { // TODO Auto-generated method stub } }); //發(fā)起截圖請(qǐng)求 mBaiduMap.snapshot(new SnapshotReadyCallback() { @Override public void onSnapshotReady(Bitmap arg0) { // TODO Auto-generated method stub } }); 五.地圖高階——圖層 1.什么是圖層 一個(gè)地圖是由很多個(gè)圖層包裹的,還有級(jí)別,這是由圖塊決定的,你所看到的房子,學(xué)校什么的都是由圖層實(shí)現(xiàn)的 2.圖層分類 底圖 基本的一個(gè)地圖包括了各種建筑啥啥啥的 實(shí)時(shí)交通圖 交通路況啥啥啥的 衛(wèi)星圖 就是從衛(wèi)星上拍下來(lái)的嘛,哈哈哈哈,這些都一筆帶過(guò)吧 其他 還有各種各樣的,比如熱力圖啥的 3.覆蓋物 覆蓋物的層級(jí)壓蓋關(guān)系,如下(從上往下) 1、基礎(chǔ)底圖(包括底圖、底圖道路、衛(wèi)星圖等); 2、地形圖圖層(GroundOverlay); 3、熱力圖圖層(HeatMap); 4、實(shí)時(shí)路況圖圖層(BaiduMap.setTrafficEnabled(true);); 5、百度城市熱力圖(BaiduMap.setBaiduHeatMapEnabled(true);); 6、底圖標(biāo)注(指的是底圖上面自帶的那些POI元素); 7、幾何圖形圖層(點(diǎn)、折線、弧線、圓、多邊形); 8、標(biāo)注圖層(Marker),文字繪制圖層(Text); 9、指南針圖層(當(dāng)?shù)貓D發(fā)生旋轉(zhuǎn)和視角變化時(shí),默認(rèn)出現(xiàn)在左上角的指南針); 10、定位圖層(BaiduMap.setMyLocationEnabled(true);); 11、彈出窗圖層(InfoWindow); 12、自定義View(MapView.addView(View);); 4.基礎(chǔ)圖層切換 我們還是模擬操作,你也可以用Button點(diǎn)擊事件去實(shí)現(xiàn),這里就直接在onKeyDown()里面迷你按123鍵進(jìn)行操作 //點(diǎn)擊屏幕切換圖層 從地圖-衛(wèi)星圖-交通圖 @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { // 底圖 case KeyEvent.KEYCODE_1: // 設(shè)置地圖類型 mBaiduMap.setMapType(mBaiduMap.MAP_TYPE_NORMAL); break; // 衛(wèi)星圖 case KeyEvent.KEYCODE_2: mBaiduMap.setMapType(mBaiduMap.MAP_TYPE_SATELLITE); break; // 交通圖 case KeyEvent.KEYCODE_3: // 交通圖是否打開(kāi) mBaiduMap.setTrafficEnabled(true); break; } return super.onKeyDown(keyCode, event); } 5.免費(fèi)申請(qǐng)標(biāo)注 有時(shí)候我們會(huì)發(fā)現(xiàn),你身處的環(huán)境附近有一些小店鋪是沒(méi)有在地圖上標(biāo)記的,也有一些小店鋪就被百度地圖給標(biāo)記了,這是為什么了?這其實(shí)是百度的一個(gè)特有的功能,也不是技術(shù)活,純粹就是跟申請(qǐng)賬號(hào)一樣 首先我們打開(kāi)百度地圖的官網(wǎng):http://map.baidu.com/ 在最下方有個(gè)不起眼的文字,商戶免費(fèi)標(biāo)注,點(diǎn)進(jìn)去 按照這個(gè)步驟免費(fèi)申請(qǐng)就得了,這里就不過(guò)多贅述 六.地圖高階——繪制覆蓋物 所有疊加或覆蓋到地圖的內(nèi)容,我們統(tǒng)稱為地圖覆蓋物。如標(biāo)注、矢量圖形元素(包括:折線和多邊形和圓)、定位圖標(biāo)等。覆蓋物擁有自己的地理坐標(biāo),當(dāng)您拖動(dòng)或縮放地圖時(shí),它們會(huì)相應(yīng)的處理。 覆蓋物包括:本地覆蓋物和搜索覆蓋物 本地覆蓋物的抽象基類:OverlayOptions(核心類) 圓形覆蓋物: CircleOptions 文字覆蓋物: TextOptions marker覆蓋物: MarkerOptions 圓點(diǎn)覆蓋物:DotOptions ground 覆蓋物:GroundOverlayOptions 圓點(diǎn)覆蓋物:DotOptions 多邊形覆蓋物:PolygonOptions 折線覆蓋物:PolylineOptions 弧線覆蓋物:ArcOptions 1.繪制圓 既然熟悉了這些基礎(chǔ)的知識(shí),那我們就先來(lái)繪制一個(gè)圓吧 寫一個(gè)drawCircle()方法讓onCreate()調(diào)用 // 繪制圓 private void drawCircle() { // 1.創(chuàng)建自己 CircleOptions circleOptions = new CircleOptions(); // 2.設(shè)置數(shù)據(jù) 以世界之窗為圓心,1000米為半徑繪制 circleOptions.center(new LatLng(22.5422870000, 113.9804440000))//中心 .radius(1000) //半徑 .fillColor(0x60FF0000)//填充圓的顏色 .stroke(new Stroke(10, 0x600FF000)); //邊框的寬度和顏色 //把繪制的圓添加到百度地圖上去 mBaiduMap.addOverlay(circleOptions); } 說(shuō)了這么多,還是沒(méi)有看圖來(lái)的實(shí)在,我們來(lái)看下截圖 2.繪制文字 同樣的我們?cè)趯懸粋€(gè)方法drawText(); // 繪制文字 private void drawText() { TextOptions textOptions = new TextOptions(); textOptions.fontColor(Color.RED) //設(shè)置字體顏色 .text("自定義文字覆蓋物") //設(shè)置顯示文本 .position(new LatLng(22.5422870000, 113.9804440000)) //設(shè)置顯示坐標(biāo) .fontSize(20) //設(shè)置文本大小 .typeface(Typeface.SERIF) //設(shè)置字體 Android的字體就三種,對(duì)稱的,不對(duì)稱的,等寬的 .rotate(30); //設(shè)置旋轉(zhuǎn)角度 //把繪制的圓添加到百度地圖上去 mBaiduMap.addOverlay(textOptions); } 截圖 3.繪制Mark覆蓋物 Mark覆蓋物就有趣多了,她是可以讓我們自定義一張圖片放上去的,就像那些打車軟件一樣可以讓地圖上看到一些車輛的信息 同樣的,不管三七二十一,我們繼續(xù)寫一個(gè)方法drawMark(); 先看看我這張要塞進(jìn)去的圖片 // 繪制mark覆蓋物 private void drawMark() { MarkerOptions markerOptions = new MarkerOptions(); BitmapDescriptor bitmap = BitmapDescriptorFactory.fromResource(R.drawable.logo); // 描述圖片 markerOptions.position(new LatLng(22.5422870000, 113.9804440000)) // 設(shè)置位置 .icon(bitmap) // 加載圖片 .draggable(true) // 支持拖拽 .title("世界之窗旁邊的草房"); // 顯示文本 //把繪制的圓添加到百度地圖上去 mBaiduMap.addOverlay(markerOptions); } 截圖 設(shè)置Mark覆蓋物點(diǎn)擊出現(xiàn)泡泡效果 不多說(shuō)啥,先上個(gè)圖給大家看看效果 實(shí)現(xiàn)這樣的一個(gè)效果,其實(shí)就是加了一個(gè)pop 我們首先得自己定義一個(gè)activity_pop.xml android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:paddingBottom="0dip" > android:id="@+id/user_info" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="20dip" android:layout_weight="1" android:background="@drawable/popupmap" android:gravity="center_vertical" android:orientation="horizontal" > android:id="@+id/round" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="2dip" android:src="@drawable/round" /> android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:ellipsize="end" android:text="標(biāo)題" android:textSize="20sp" /> android:id="@+id/roads" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/roads" /> 預(yù)覽是這樣子的 首先,我們得初始化一些變量 //要顯示的pop private View pop; //pop中的文本信息 private TextView title; pop的初始化 //初始化pop private void initPop() { pop = View.inflate(getApplicationContext(), R.layout.activity_pop, null); //必須使用百度的params LayoutParams params = new MapViewLayoutParams.Builder().layoutMode(MapViewLayoutParams.ELayoutMode.mapMode) //按照經(jīng)緯度設(shè)置 .position(new LatLng(22.5422870000, 113.9804440000)) //這個(gè)坐標(biāo)無(wú)所謂的,但是不能傳null .width(MapViewLayoutParams.WRAP_CONTENT) //寬度 .height(MapViewLayoutParams.WRAP_CONTENT) //高度 .build(); mMapView.addView(pop,params); //先設(shè)置隱藏,點(diǎn)擊的時(shí)候顯示 pop.setVisibility(View.INVISIBLE); //初始化這個(gè)title title = (TextView) pop.findViewById(R.id.title); } mark的點(diǎn)擊事件 /**mark的點(diǎn)擊事件 * 點(diǎn)擊某一個(gè)mark在他上放顯示泡泡 * 加載pop 添加到mapview 把他設(shè)置為隱藏 當(dāng)點(diǎn)擊的時(shí)候更新pop的位置 設(shè)置為顯示 */ mBaiduMap.setOnMarkerClickListener(new OnMarkerClickListener() { @Override public boolean onMarkerClick(Marker result) { //處理點(diǎn)擊 ,當(dāng)點(diǎn)擊的時(shí)候更新并且顯示位置 LayoutParams params = new MapViewLayoutParams.Builder(). layoutMode(MapViewLayoutParams.ELayoutMode.mapMode) //按照經(jīng)緯度設(shè)置位置 .position(result.getPosition()) //這個(gè)坐標(biāo)無(wú)所謂的,但是不能傳null .width(MapViewLayoutParams.WRAP_CONTENT) //寬度 .height(MapViewLayoutParams.WRAP_CONTENT) //高度 .yOffset(-5) //相距 正值往下 負(fù)值往上 .build(); mMapView.updateViewLayout(pop, params); pop.setVisibility(View.VISIBLE); //更新下title title.setText(result.getTitle()); return true; } }); ``` 這邊新加一個(gè)功能,就是泡泡輪播切換,咱先看效果圖: 其實(shí)實(shí)現(xiàn)這個(gè)不難,就是在設(shè)置icon的時(shí)候設(shè)置一個(gè)icons穿進(jìn)去一個(gè)Bitmap的list //拿上面那個(gè)方法直接改的設(shè)置icon // 繪制mark覆蓋物 private void drawMark() { MarkerOptions markerOptions = new MarkerOptions(); BitmapDescriptor bitmap = BitmapDescriptorFactory.fromResource(R.drawable.logo); // 描述圖片 ArrayList bitmaps.add(bitmap); //顯示多個(gè)圖片的來(lái)回切換,類似于幀動(dòng)畫 bitmaps.add(BitmapDescriptorFactory.fromResource(R.drawable.icon_geo)); markerOptions.position(new LatLng(22.5422870000, 113.9804440000)) // 設(shè)置位置 //.icon(bitmap) // 加載圖片 //切換圖片 .icons(bitmaps) .period(10) //切換時(shí)間 .draggable(true) // 支持拖拽 .title("世界之窗旁邊的草房"); // 顯示文本 mBaiduMap.addOverlay(markerOptions); } ``` 好的,Mark覆蓋物寫得差不多了 ,繼續(xù)往下看吧 七.地圖高階——搜索路線標(biāo)記 真不好意思,最近一直在加班,空閑的時(shí)間越來(lái)越少,沒(méi)事,記錄擼代碼!?。?/p> 接下來(lái)講的是路線標(biāo)記,相信不少人應(yīng)該知道,地圖導(dǎo)航的時(shí)候會(huì)幫你標(biāo)記一條路線,我們今天就來(lái)實(shí)現(xiàn)這個(gè)功能,后續(xù)有哪些方法有疏漏,也希望博友能指點(diǎn)出來(lái),畢竟我也是技術(shù)渣渣 百度地圖移動(dòng)版API集成搜索服務(wù)包括: 位置檢索、周邊檢索、范圍檢索、公交檢索、駕乘檢索、步行檢索 核心類: PoiSearch和OnGetPoiSearchResultListener RoutePlanSearch和OnGetRoutePlanResultListener 實(shí)現(xiàn)思路 初始化PoiSearch類,通過(guò)setOnGetPoiSearchResultListener方法注冊(cè)搜索結(jié)果的監(jiān)聽(tīng)對(duì)象OnGetPoiSearchResultListener ,實(shí)現(xiàn)異步搜索服務(wù)。 通過(guò)自定義MySearchListener實(shí)現(xiàn)類,處理不同的回調(diào)方法,獲得搜索結(jié)果。 注意, OnGetPoiSearchResultListener只支持一個(gè),以最后一次設(shè)置為準(zhǔn) 結(jié)合覆蓋物展示搜索 本地搜索覆蓋物:PoiOverlay 駕車路線覆蓋物:DrivingRouteOverlay 步行路線覆蓋物:WalkingRouteOverlay 換乘路線覆蓋物:TransitOverlay 1.范圍搜索,PoiOverlay的點(diǎn)擊事件(矩形) 我們直接寫一個(gè)search()方法讓onCreate()調(diào)用吧 直接擼代碼,實(shí)現(xiàn)search(); // 范圍搜索 private void search() { // 實(shí)例化搜索方法 PoiSearch newInstance = PoiSearch.newInstance(); newInstance.setOnGetPoiSearchResultListener(new SearchListener()); // 發(fā)出搜索的請(qǐng)求 范圍檢索 PoiBoundSearchOption boundOption = new PoiBoundSearchOption(); LatLngBounds latLngBounds = new LatLngBounds.Builder() // 確定兩點(diǎn)坐標(biāo)(東北,西南) // 這里我們隨機(jī)弄兩個(gè)坐標(biāo) 分別是深圳世界之窗附近 .include(new LatLng(22.5441560000, 113.9828800000)) // 世界之窗右上角的美加廣場(chǎng) .include(new LatLng(22.5413850000, 113.9777770000)) // 世界之窗左下角的一個(gè)不知道叫啥的街道 .build(); boundOption.bound(latLngBounds); // 設(shè)置搜索的范圍 boundOption.keyword("世界之窗"); // 搜索的關(guān)鍵字 newInstance.searchInBound(boundOption); } 實(shí)現(xiàn)它的Listener class SearchListener implements OnGetPoiSearchResultListener { @Override public void onGetPoiDetailResult(PoiDetailResult result) { } @Override public void onGetPoiResult(PoiResult result) { // 收到發(fā)送過(guò)來(lái)的搜索請(qǐng)求之后我們進(jìn)行處理 if(result == null || SearchResult.ERRORNO.RESULT_NOT_FOUND == result.error){ Toast.makeText(getApplicationContext(), "未搜索到結(jié)果", Toast.LENGTH_LONG).show(); return; } //搜索類型的類 PoiOverlay overlay = PoiOverlay(mBaiduMap); //處理搜索Poi的覆蓋物 mBaiduMap.setOnMarkerClickListener(overlay);// 把事件分發(fā)給overlay,overlay才能處理點(diǎn)擊事件 overlay.setData(result); //設(shè)置結(jié)果 overlay.addToMap;//把搜索的結(jié)果添加到地圖中去 overlay.zoomToSpan(); //自動(dòng)縮放到所以的mark覆蓋物都能看到 } } 自己實(shí)現(xiàn)它的點(diǎn)擊事件 //自己實(shí)現(xiàn)點(diǎn)擊事件 class MyPoiOverlay extends PoiOverlay { public MyPoiOverlay(BaiduMap arg0) { super(arg0); } @Override public boolean onPoiClick(int index) { PoiResult poiResult = getPoiResult(); PoiInfo poiInfo = poiResult.getAllPoi().get(index);// 得到點(diǎn)擊的那個(gè)poi信息 String text = poiInfo.name + "," + poiInfo.address; Toast.makeText(getApplicationContext(), text, 0).show(); return super.onPoiClick(index); } } 官方的效果,點(diǎn)擊后Toast 2.周邊搜索(圓形) 周邊搜索和范圍搜索基本一致,我就直接上代碼了 private void search() { poiSearch = PoiSearch.newInstance(); poiSearch.setOnGetPoiSearchResultListener(new MyListener()); PoiNearbySearchOption nearbyOption = new PoiNearbySearchOption(); nearbyOption.location(hmPos);// 設(shè)置中心點(diǎn) nearbyOption.radius(1000);// 設(shè)置半徑 單位是米 nearbyOption.keyword("加油站");// 關(guān)鍵字 poiSearch.searchNearby(nearbyOption); } class MyListener implements OnGetPoiSearchResultListener{ @Override public void onGetPoiDetailResult(PoiDetailResult result) { if(result==null||SearchResult.ERRORNO.RESULT_NOT_FOUND==result.error){ Toast.makeText(getApplicationContext(), "未搜索到結(jié)果", 0).show(); return; } String text = result.getAddress()+ "::" + result.getCommentNum() + result.getEnvironmentRating(); Toast.makeText(getApplicationContext(), text, 0).show(); } @Override public void onGetPoiResult(PoiResult result) { if(result==null||SearchResult.ERRORNO.RESULT_NOT_FOUND==result.error){ Toast.makeText(getApplicationContext(), "未搜索到結(jié)果", 0).show(); return; } PoiOverlay overlay = new MyPoiOverlay(baiduMap);// 搜索poi的覆蓋物 baiduMap.setOnMarkerClickListener(overlay);// 把事件分發(fā)給overlay,overlay才能處理點(diǎn)擊事件 overlay.setData(result);// 設(shè)置結(jié)果 overlay.addToMap();// 把搜索的結(jié)果添加到地圖中 overlay.zoomToSpan();// 縮放地圖,使所有Overlay都在合適的視野內(nèi) 注: 該方法只對(duì)Marker類型的overlay有效 } } class MyPoiOverlay extends PoiOverlay { public MyPoiOverlay(BaiduMap arg0) { super(arg0); } @Override public boolean onPoiClick(int index) { PoiResult poiResult = getPoiResult(); PoiInfo poiInfo = poiResult.getAllPoi().get(index);// 得到點(diǎn)擊的那個(gè)poi信息 String text = poiInfo.name + "," + poiInfo.address; Toast.makeText(getApplicationContext(), text, 0).show(); PoiDetailSearchOption detailOption = new PoiDetailSearchOption(); detailOption.poiUid(poiInfo.uid);// 設(shè)置poi的uid poiSearch.searchPoiDetail(detailOption); return super.onPoiClick(index); } } 3.城市內(nèi)搜索 基本上是一摸一樣的 private PoiSearch poiSearch; private int currentPageIndex = 0; private void search() { poiSearch = PoiSearch.newInstance(); poiSearch.setOnGetPoiSearchResultListener(new MyListener()); search(); PoiCitySearchOption cityOption = new PoiCitySearchOption(); cityOption.city("北京"); cityOption.keyword("加油站"); cityOption.pageNum(currentPageIndex); poiSearch.searchInCity(cityOption); } class MyListener implements OnGetPoiSearchResultListener { @Override public void onGetPoiDetailResult(PoiDetailResult result) { } @Override public void onGetPoiResult(PoiResult result) { if (result == null || SearchResult.ERRORNO.RESULT_NOT_FOUND == result.error) { Toast.makeText(getApplicationContext(), "未搜索到結(jié)果", 0).show(); return; } String text = "共" + result.getTotalPageNum() + "頁(yè),共" + result.getTotalPoiNum() + "條,當(dāng)前第" + result.getCurrentPageNum() + "頁(yè),當(dāng)前頁(yè)" + result.getCurrentPageCapacity() + "條"; Toast.makeText(getApplicationContext(), text, 1).show(); baiduMap.clear();// 清空地圖所有的 Overlay 覆蓋物以及 InfoWindow PoiOverlay overlay = new MyPoiOverlay(baiduMap);// 搜索poi的覆蓋物 baiduMap.setOnMarkerClickListener(overlay);// 把事件分發(fā)給overlay,overlay才能處理點(diǎn)擊事件 overlay.setData(result);// 設(shè)置結(jié)果 overlay.addToMap();// 把搜索的結(jié)果添加到地圖中 overlay.zoomToSpan();// 縮放地圖,使所有Overlay都在合適的視野內(nèi) 注: // 該方法只對(duì)Marker類型的overlay有效 } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if(keyCode==KeyEvent.KEYCODE_1){ currentPageIndex++; search(); } return super.onKeyDown(keyCode, event); } class MyPoiOverlay extends PoiOverlay { public MyPoiOverlay(BaiduMap arg0) { super(arg0); } @Override public boolean onPoiClick(int index) { PoiResult poiResult = getPoiResult(); PoiInfo poiInfo = poiResult.getAllPoi().get(index);// 得到點(diǎn)擊的那個(gè)poi信息 String text = poiInfo.name + "," + poiInfo.address; Toast.makeText(getApplicationContext(), text, 0).show(); return super.onPoiClick(index); } } ``` 4.路線檢索(駕車路線) //駕車路線 private void driving(){ RoutePlanSearch newInstance = RoutePlanSearch.newInstance(); newInstance.setOnGetRoutePlanResultListener(new MyListener()); //駕車路線 DrivingRoutePlanOption drivingOption = new DrivingRoutePlanOption(); PlanNode from = PlanNode.withLocation(new LatLng(22.5422870000, 113.9804440000)); //設(shè)置起點(diǎn)世界之窗 PlanNode to = PlanNode.withLocation(new LatLng(22.5455910000,113.9880900000)); //設(shè)置終點(diǎn)就附近的歡樂(lè)谷 drivingOption.from(from); drivingOption.to(to); drivingOption.policy(DrivingRoutePlanOption.DrivingPolicy.ECAR_DIS_FIRST); //方案:最短距離 這個(gè)自己設(shè)置 比如時(shí)間短之類的 newInstance.drivingSearch(drivingOption); } class MyListener implements OnGetRoutePlanResultListener{ @Override public void onGetDrivingRouteResult(DrivingRouteResult result) { //駕車 if(result == null || SearchResult.ERRORNO.RESULT_NOT_FOUND == result.error){ Toast.makeText(getApplicationContext(), "未搜索到結(jié)果", Toast.LENGTH_LONG).show(); return; } //開(kāi)始處理結(jié)果了 DrivingRouteOverlay overlay = new MyDrivingOverlay(baiduMap); baiduMap.setOnMarkerClickListener(overlay);// 把事件傳遞給overlay overlay.setData(result.getRouteLines().get(0));// 設(shè)置線路為第一條 overlay.addToMap(); overlay.zoomToSpan(); } @Override public void onGetTransitRouteResult(TransitRouteResult result) { // 公交換乘 } @Override public void onGetWalkingRouteResult(WalkingRouteResult result) { // 步行 } } class MyDrivingOverlay extends DrivingRouteOverlay{ public MyDrivingOverlay(BaiduMap arg0) { super(arg0); } @Override public BitmapDescriptor getStartMarker() { //覆寫此方法以改變默認(rèn)起點(diǎn)圖標(biāo) return BitmapDescriptorFactory.fromResource(R.drawable.icon_st); } @Override public BitmapDescriptor getTerminalMarker() { //覆寫此方法以改變默認(rèn)終點(diǎn)圖標(biāo) return BitmapDescriptorFactory.fromResource(R.drawable.icon_en); } } 官方的效果圖 5.6.公交換乘和步行路線,其實(shí)和駕車路線的寫法是一樣的這里就不寫了 寫的時(shí)候不知道為什么我的Overlay類來(lái)是創(chuàng)建不出來(lái),所以代碼拙劣的地方還請(qǐng)海涵 八.地圖高階——定位系統(tǒng) 這個(gè)相信是大家經(jīng)常用到的 LocationClient和BDLocationListener 首先需要打開(kāi)定位圖層BaiduMap.setMyLocationEnabled(true); 設(shè)置監(jiān)聽(tīng)器LocationClient. registerLocationListener(BDLocationListener) 設(shè)置定位模式baiduMap. setLocationMode(LocationMode) Hight_Accuracy,高精度定位模式:這種定位模式下,會(huì)同時(shí)使用網(wǎng)絡(luò)定位和GPS定位,優(yōu)先返回最高精度的定位結(jié)果; Battery_Saving,低功耗定位模式:這種定位模式下,不會(huì)使用GPS,只會(huì)使用網(wǎng)絡(luò)定位(Wi-Fi和基站定位) Device_Sensors,僅用設(shè)備定位模式:這種定位模式下,不需要連接網(wǎng)絡(luò),只使用GPS進(jìn)行定位,這種模式下不支持室內(nèi)環(huán)境的定位 設(shè)置定位顯示模式BaiduMap.setMyLocationConfigeration(MyLocationConfiguration) 定位數(shù)據(jù)獲?。涸贐DLocationListener. onReceiveLocation(BDLocation result)方法中設(shè)置定位數(shù)據(jù), baiduMap.setMyLocationData(MyLocationData); 一個(gè)GPS定位,不過(guò)必須要三顆星以上才可定位,不然是定不了的,還有一個(gè)基站地位,他其實(shí)每個(gè)基站都有一個(gè)ID,就是一個(gè)位置,查到最近基站的位置然后去服務(wù)器里請(qǐng)求返回位置信息,還有一個(gè)wifi定位,當(dāng)你的手機(jī)連接wifi,你開(kāi)始定位的時(shí)候,把wifi的地址發(fā)送到百度的服務(wù)器,服務(wù)器會(huì)把大部分wifi地址都有收錄,直接返回經(jīng)緯度 地址:http://developer.baidu.com/map/index.php?title=android-locsdk/guide/v5-0 我們根據(jù)百度提供的文檔去做 1.在application標(biāo)簽中聲明service組件,每個(gè)app擁有自己?jiǎn)为?dú)的定位service android:enabled="true" //跑在一個(gè)新的進(jìn)程中 android:process=":remote"> 主要用到的兩個(gè)類 public LocationClient mLocationClient; public BDLocationListener myListener; private BitmapDescriptor geo; 然后我們直接寫個(gè)方法lacate(); private void lacate() { mLocationClient = new LocationClient(getApplicationContext()); myListener = new MyListener(); mLocationClient.registerLocationListener(myListener); LocationClientOption option = new LocationClientOption(); option.setLocationMode(LocationMode.Hight_Accuracy);// 設(shè)置定位模式 option.setCoorType("bd09ll");// 返回的定位結(jié)果是百度經(jīng)緯度,默認(rèn)值gcj02 option.setScanSpan(5000);// 設(shè)置發(fā)起定位請(qǐng)求的間隔時(shí)間為5000ms option.setIsNeedAddress(true);// 返回的定位結(jié)果包含地址信息 option.setNeedDeviceDirect(true);// 返回的定位結(jié)果包含手機(jī)機(jī)頭的方向 mLocationClient.setLocOption(option); geo = BitmapDescriptorFactory .fromResource(R.drawable.icon_geo); MyLocationConfiguration configuration = new MyLocationConfiguration( MyLocationConfiguration.LocationMode.FOLLOWING, true, geo); baiduMap.setMyLocationConfigeration(configuration);// 設(shè)置定位顯示的模式 baiduMap.setMyLocationEnabled(true);// 打開(kāi)定位圖層 } 繼續(xù)自己寫個(gè)Listener class MyListener implements BDLocationListener { @Override public void onReceiveLocation(BDLocation result) { if (result != null) { MyLocationData data = new MyLocationData.Builder() .latitude(result.getLatitude()) .longitude(result.getLongitude()).build(); baiduMap.setMyLocationData(data); } } } 我們可以模擬一下使用各種方式去定位 @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_1: // 正常 baiduMap.setMyLocationConfigeration(new MyLocationConfiguration( MyLocationConfiguration.LocationMode.NORMAL, true, geo));// 設(shè)置定位顯示的模式 break; case KeyEvent.KEYCODE_2: // 羅盤 baiduMap.setMyLocationConfigeration(new MyLocationConfiguration( MyLocationConfiguration.LocationMode.COMPASS, true, geo));// 設(shè)置定位顯示的模式 break; case KeyEvent.KEYCODE_3: // 跟隨 baiduMap.setMyLocationConfigeration(new MyLocationConfiguration( MyLocationConfiguration.LocationMode.FOLLOWING, true, geo));// 設(shè)置定位顯示的模式 break; default: break; } return super.onKeyDown(keyCode, event); } 百度地圖算是寫完一半了,為什么說(shuō)只寫完了一半,因?yàn)闀r(shí)間緊迫,里面肯定會(huì)有些錯(cuò)誤的編寫,不過(guò)思想是對(duì)的,你按照步驟來(lái),結(jié)合你對(duì)百度API的認(rèn)知,這些其實(shí)都是很簡(jiǎn)單就去實(shí)現(xiàn)的,這里只是作為一個(gè)拋磚引玉 后續(xù)還會(huì)持續(xù)修訂更改,如有錯(cuò)誤,歡迎點(diǎn)評(píng),謝謝了! Demo下載地址:http://download.csdn.net/detail/qq_26787115/9379582 |