有錢人咱就不說了,由於偶是個窮銀……由於窮,因此去年買的Huawei C8650+到如今還在上崗,對於沒有錢買好的配置的手機的童鞋來講,相似於百度,谷歌,高德等商家的地圖在本身的機器上跑起來確實是有點勉爲其難,爲了可以用上手機的地圖,並不怎麼大,最近閒來無事,就動起了這方面的腦筋,結果就是用百度地圖API開發一個本身想要的功能的地圖……html
這是通過一點時間倒騰後的一點點小成果,實現了自定義的放大縮小按鈕,GPS定位,GPS當前位置500m範圍內關鍵字的搜索。下面這張截圖說明了上面提到的幾個功能,其中個人搜索關鍵字爲「公交」……java
嗯,看完效果說說個人具體實現吧。下圖爲工程的目錄結構:android
源代碼以下:git
MainActivity.java
api
package com.lzugis.mymap; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.os.Bundle; import android.util.Log; import android.view.Gravity; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; import android.graphics.Bitmap; import com.baidu.location.BDLocation; import com.baidu.location.BDLocationListener; import com.baidu.location.LocationClient; import com.baidu.location.LocationClientOption; import com.baidu.mapapi.BMapManager; import com.baidu.mapapi.MKGeneralListener; import com.baidu.mapapi.search.MKSearch; import com.baidu.mapapi.search.MKAddrInfo; import com.baidu.mapapi.search.MKBusLineResult; import com.baidu.mapapi.search.MKDrivingRouteResult; import com.baidu.mapapi.search.MKPoiResult; import com.baidu.mapapi.search.MKSearchListener; import com.baidu.mapapi.search.MKShareUrlResult; import com.baidu.mapapi.search.MKSuggestionResult; import com.baidu.mapapi.search.MKTransitRouteResult; import com.baidu.mapapi.search.MKWalkingRouteResult; import com.baidu.mapapi.map.LocationData; import com.baidu.mapapi.map.MKEvent; import com.baidu.mapapi.map.MKMapViewListener; import com.baidu.mapapi.map.MapController; import com.baidu.mapapi.map.MapPoi; import com.baidu.mapapi.map.MapView; import com.baidu.mapapi.map.MyLocationOverlay; import com.baidu.mapapi.map.PoiOverlay; import com.baidu.mapapi.map.PopupClickListener; import com.baidu.mapapi.map.PopupOverlay; import com.baidu.platform.comapi.basestruct.GeoPoint; import com.lzugis.myview.SearchControlView; import com.lzugis.myview.ZoomControlView; import com.org.baidumap.R; public class MainActivity extends Activity { //地圖顯示 private BMapManager mBMapMan = null; private MapView mMapView = null; private MapController mMapController = null; //提示信息 private Toast toast; //獲取當前位置 private Button currentloc; //Poi查詢 //定位SDK的核心類 private LocationClient mLocClient; //用戶位置信息 private LocationData mLocData; //個人位置圖層 private LocationOverlay myLocationOverlay = null; //彈出窗口圖層 private PopupOverlay mPopupOverlay = null; //是否手動觸發請求定位 private boolean isRequest = false; //是否首次定位 private boolean isFirstLoc = true; //POI搜索 private MKSearch mMKSearch; //放大縮小控件 private ZoomControlView mZoomControlView; //搜索控件 private SearchControlView mSearchControlView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mBMapMan=new BMapManager(getApplication()); //開發受權碼 String strKey="wNdy48s7V1izbLL0ziswArXq"; mBMapMan.init(strKey, new MKGeneralListenerImpl()); //注意:請在試用setContentView前初始化BMapManager對象,不然會報錯 setContentView(R.layout.main); mMapView=(MapView)findViewById(R.id.bmapsView); //不顯示內置縮放控件 mMapView.setBuiltInZoomControls(false); //設置交通訊息圖可見 mMapView.setTraffic(true); //獲得mMapView的控制權,能夠用它控制和驅動平移和縮放 mMapController=mMapView.getController(); //用給定的經緯度構造一個GeoPoint,單位是微度 (度 * 1E6) GeoPoint point =new GeoPoint((int)(40.805* 1E6),(int)(111.661* 1E6)); //設置地圖中心點 mMapController.setCenter(point); //設置地圖zoom級別 mMapController.setZoom(12); //用戶自定義放大縮小控件初始化 mZoomControlView = (ZoomControlView) findViewById(R.id.ZoomControlView); mZoomControlView.setMapView(mMapView); //用戶自定義搜索控件初始化 mMKSearch = new MKSearch(); mMKSearch.init(mBMapMan, new MySearchListener()); mSearchControlView=(SearchControlView)findViewById(R.id.SearchControlView); mSearchControlView.setMapView(mMapView); mSearchControlView.setMapController(mMapController); mSearchControlView.setMKSearch(mMKSearch); //地圖顯示事件監聽器。 該接口監聽地圖顯示事件,用戶須要實現該接口以處理相應事件。 mMapView.regMapViewListener(mBMapMan, new MKMapViewListener() { @Override //地圖移動結束時 public void onMapMoveFinish() { refreshZoomControl(); } @Override //地圖加載結束時 public void onMapLoadFinish() { } @Override public void onMapAnimationFinish() { refreshZoomControl(); } @Override public void onGetCurrentMap(Bitmap arg0) { } @Override public void onClickMapPoi(MapPoi arg0) { } }); //實例化彈出窗口圖層 mPopupOverlay = new PopupOverlay(mMapView ,new PopupClickListener() { /** * 點擊彈出窗口圖層回調的方法 */ @Override public void onClickedPopup(int arg0) { //隱藏彈出窗口圖層 mPopupOverlay.hidePop(); } }); mLocClient = new LocationClient(getApplicationContext()); mLocClient.registerLocationListener(new BDLocationListenerImpl());//註冊定位監聽接口 /** * LocationClientOption 該類用來設置定位SDK的定位方式。 */ LocationClientOption option = new LocationClientOption(); option.setOpenGps(true); //打開GPRS option.setAddrType("all");//返回的定位結果包含地址信息 option.setCoorType("bd09ll");//返回的定位結果是百度經緯度,默認值gcj02 option.setPriority(LocationClientOption.GpsFirst); // 設置GPS優先 option.setScanSpan(5000); //設置發起定位請求的間隔時間爲5s option.disableCache(true);//啓用緩存定位 mLocClient.setLocOption(option); //設置定位參數 //定位圖層初始化 myLocationOverlay = new LocationOverlay(mMapView); //實例化定位數據,並設置在個人位置圖層 mLocData = new LocationData(); myLocationOverlay.setData(mLocData); //添加定位圖層 mMapView.getOverlays().add(myLocationOverlay); //修改定位數據後刷新圖層生效 mMapView.refresh(); toast = Toast.makeText(getApplicationContext(), "", Toast.LENGTH_LONG); currentloc=(Button)findViewById(R.id.currentloc); currentloc.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { mLocClient.start(); //調用此方法開始定位 requestLocation(); } }); toast.setText(R.string.load_message); toast.setGravity(Gravity.CENTER, 0, 0); toast.show(); } private void refreshZoomControl() { //更新縮放按鈕的狀態 mZoomControlView.refreshZoomButtonStatus(Math.round(mMapView.getZoomLevel())); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } public boolean onOptionsItemSelected(MenuItem item) { switch(item.getItemId()) { case R.id.menu_settings: { toast.setText("軟件設置"); toast.setGravity(Gravity.BOTTOM, 0, 0); toast.show(); break; } default: { exitAlert("真的要退出個人地圖嗎?"); break; } } return true; } private void exitAlert(String msg) { //實例化 AlertDialog.Builder builder=new AlertDialog.Builder(this); builder.setMessage(msg) .setCancelable(false) .setPositiveButton("肯定", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub finish(); } }) .setNegativeButton("取消", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub return; } }); AlertDialog alert=builder.create(); alert.show(); } @Override protected void onResume() { //MapView的生命週期與Activity同步,當activity掛起時需調用MapView.onPause() mMapView.onResume(); super.onResume(); } @Override protected void onPause() { //MapView的生命週期與Activity同步,當activity掛起時需調用MapView.onPause() mMapView.onPause(); super.onPause(); } @Override protected void onDestroy() { //MapView的生命週期與Activity同步,當activity銷燬時需調用MapView.destroy() mMapView.destroy(); //退出應用調用BMapManager的destroy()方法 if(mBMapMan != null) { mBMapMan.destroy(); mBMapMan = null; } //退出時銷燬定位 if (mLocClient != null) { mLocClient.stop(); } super.onDestroy(); } /** * * @author lzugis * */ public class BDLocationListenerImpl implements BDLocationListener { /** * 接收異步返回的定位結果,參數是BDLocation類型參數 */ @Override public void onReceiveLocation(BDLocation location) { //設置location mSearchControlView.setBDLocation(location); if (location == null) { return; } StringBuffer sb = new StringBuffer(256); sb.append("time : "); sb.append(location.getTime()); sb.append("\nerror code : "); sb.append(location.getLocType()); sb.append("\nlatitude : "); sb.append(location.getLatitude()); sb.append("\nlontitude : "); sb.append(location.getLongitude()); sb.append("\nradius : "); sb.append(location.getRadius()); if (location.getLocType() == BDLocation.TypeGpsLocation) { sb.append("\nspeed : "); sb.append(location.getSpeed()); sb.append("\nsatellite : "); sb.append(location.getSatelliteNumber()); } else if (location.getLocType() == BDLocation.TypeNetWorkLocation) { sb.append("\naddr : "); sb.append(location.getAddrStr()); } Log.e("log", sb.toString()); mLocData.latitude = location.getLatitude(); mLocData.longitude = location.getLongitude(); //若是不顯示定位精度圈,將accuracy賦值爲0便可 mLocData.accuracy = location.getRadius(); mLocData.direction = location.getDerect(); //將定位數據設置到定位圖層裏 myLocationOverlay.setData(mLocData); //更新圖層數據執行刷新後生效 mMapView.refresh(); if(isFirstLoc || isRequest) { //將給定的位置點以動畫形式移動至地圖中心 mMapController.animateTo(new GeoPoint( (int) (location.getLatitude() * 1e6), (int) (location .getLongitude() * 1e6))); isRequest = false; } isFirstLoc = false; } /** * 接收異步返回的POI查詢結果,參數是BDLocation類型參數 */ @Override public void onReceivePoi(BDLocation poiLocation) { } } /** * * @author lzugis * */ private class LocationOverlay extends MyLocationOverlay { public LocationOverlay(MapView arg0) { super(arg0); } /** * 在「個人位置」座標上處理點擊事件。 */ @Override protected boolean dispatchTap() { //點擊個人位置顯示PopupOverlay return super.dispatchTap(); } } /** * * @author lzugis * */ public void requestLocation() { isRequest = true; if(mLocClient != null && mLocClient.isStarted()) { showToast("GPS正在定位……"); mLocClient.requestLocation(); } else { Log.d("log", "locClient is null or not started"); } } /** * * @author lzugis * */ private void showToast(String msg) { if(toast == null) { toast = Toast.makeText(this, msg, Toast.LENGTH_SHORT); } else { toast.setText(msg); toast.setDuration(Toast.LENGTH_SHORT); } toast.show(); } /** * * @author lzugis * */ public class MKGeneralListenerImpl implements MKGeneralListener { /** * 一些網絡狀態的錯誤處理回調函數 */ @Override public void onGetNetworkState(int iError) { if (iError == MKEvent.ERROR_NETWORK_CONNECT) { showToast("您的網絡出錯啦!"); } } /** * 受權錯誤的時候調用的回調函數 */ @Override public void onGetPermissionState(int iError) { if (iError == MKEvent.ERROR_PERMISSION_DENIED) { showToast("API KEY錯誤, 請檢查!"); } } } public class MySearchListener implements MKSearchListener { @Override public void onGetAddrResult(MKAddrInfo result, int iError) { } @Override public void onGetDrivingRouteResult(MKDrivingRouteResult result, int iError) { } @Override public void onGetPoiResult(MKPoiResult result, int type, int iError) { if (result == null) { return; } // PoiOverlay poioverlay = new PoiOverlay(MainActivity.this, mMapView); // poioverlay.setData(result.getAllPoi()); // mMapView.getOverlays().add(poioverlay); } @Override public void onGetBusDetailResult(MKBusLineResult arg0, int arg1) { // TODO Auto-generated method stub } @Override public void onGetPoiDetailSearchResult(int arg0, int arg1) { // TODO Auto-generated method stub } @Override public void onGetShareUrlResult(MKShareUrlResult arg0, int arg1, int arg2) { // TODO Auto-generated method stub } @Override public void onGetSuggestionResult(MKSuggestionResult arg0, int arg1) { // TODO Auto-generated method stub } @Override public void onGetTransitRouteResult(MKTransitRouteResult arg0, int arg1) { // TODO Auto-generated method stub } @Override public void onGetWalkingRouteResult(MKWalkingRouteResult arg0, int arg1) { // TODO Auto-generated method stub } } }SearchControlView.java
緩存package com.lzugis.myview; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.RelativeLayout; import com.baidu.location.BDLocation; import com.baidu.mapapi.map.MapController; import com.baidu.mapapi.map.MapView; import com.baidu.mapapi.search.MKSearch; import com.baidu.platform.comapi.basestruct.GeoPoint; import com.org.baidumap.R; public class SearchControlView extends RelativeLayout implements OnClickListener { private MapView mapView; private MKSearch mMKSearch; private BDLocation location; private MapController mMapController; private EditText txtSearch; private Button mButtonSearch; public SearchControlView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public SearchControlView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init() { View view = LayoutInflater.from(getContext()).inflate(R.layout.search_controls_layout, null); txtSearch=(EditText)view.findViewById(R.id.edittextSearch); mButtonSearch = (Button) view.findViewById(R.id.search); mButtonSearch.setOnClickListener(this); addView(view); } @Override public void onClick(View arg0) { // TODO Auto-generated method stub if(mapView == null) { throw new NullPointerException("you can call setMapView(MapView mapView) at first"); } GeoPoint geoPoint = new GeoPoint((int) (location.getLatitude() * 1e6), (int) (location.getLongitude() * 1e6)); mapView.getController().animateTo(geoPoint); String strSearch=txtSearch.getText().toString(); mMKSearch.poiSearchNearBy(strSearch, geoPoint, 500); //設置地圖中心點 mMapController.setCenter(geoPoint); //設置地圖zoom級別 mMapController.setZoom(16); } /** * 與MapView設置關聯 * @param mapView */ public void setMapView(MapView mapView) { this.mapView = mapView; } public void setBDLocation(BDLocation location) { this.location = location; } public void setMKSearch(MKSearch mMKSearch) { this.mMKSearch = mMKSearch; } public void setMapController(MapController mMapController) { this.mMapController = mMapController; } }
ZoomControlView.java
網絡package com.lzugis.myview; import com.baidu.mapapi.map.MapView; import com.org.baidumap.R; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.Button; import android.widget.RelativeLayout; import android.view.View.OnClickListener; public class ZoomControlView extends RelativeLayout implements OnClickListener{ private Button mButtonZoomin; private Button mButtonZoomout; private MapView mapView; private int maxZoomLevel; private int minZoomLevel; public ZoomControlView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public ZoomControlView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init() { View view = LayoutInflater.from(getContext()).inflate(R.layout.zoom_controls_layout, null); mButtonZoomin = (Button) view.findViewById(R.id.zoomin); mButtonZoomout = (Button) view.findViewById(R.id.zoomout); mButtonZoomin.setOnClickListener(this); mButtonZoomout.setOnClickListener(this); addView(view); } @Override public void onClick(View v) { if(mapView == null){ throw new NullPointerException("you can call setMapView(MapView mapView) at first"); } switch (v.getId()) { case R.id.zoomin:{ mapView.getController().zoomIn(); break; } case R.id.zoomout:{ mapView.getController().zoomOut(); break; } } } /** * 與MapView設置關聯 * @param mapView */ public void setMapView(MapView mapView) { this.mapView = mapView; // 獲取最大的縮放級別 maxZoomLevel = mapView.getMaxZoomLevel(); // 獲取最大的縮放級別 minZoomLevel = mapView.getMinZoomLevel(); } /** * 根據MapView的縮放級別更新縮放按鈕的狀態,當達到最大縮放級別,設置mButtonZoomin * 爲不能點擊,反之設置mButtonZoomout * @param level */ public void refreshZoomButtonStatus(int level){ if(mapView == null){ throw new NullPointerException("you can call setMapView(MapView mapView) at first"); } if(level > minZoomLevel && level < maxZoomLevel){ if(!mButtonZoomout.isEnabled()){ mButtonZoomout.setEnabled(true); } if(!mButtonZoomin.isEnabled()){ mButtonZoomin.setEnabled(true); } } else if(level == minZoomLevel ){ mButtonZoomout.setEnabled(false); } else if(level == maxZoomLevel){ mButtonZoomin.setEnabled(false); } } }location_selector.xml
app<?xml version="1.0" encoding="UTF-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" android:drawable="@drawable/location_press"></item> <item android:drawable="@drawable/location_normal"></item> </selector>search_selector.xml
ssh<?xml version="1.0" encoding="UTF-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" android:drawable="@drawable/search_press"></item> <item android:drawable="@drawable/search_normal"></item> </selector>zoomin_seletor.xml
異步<?xml version="1.0" encoding="UTF-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" android:drawable="@drawable/zoomin_press"></item> <item android:state_enabled="false" android:drawable="@drawable/zoomin_disable"></item> <item android:drawable="@drawable/zoomin_normal"></item> </selector>zoomout_seletor.xml
<?xml version="1.0" encoding="UTF-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" android:drawable="@drawable/zoomout_press"></item> <item android:state_enabled="false" android:drawable="@drawable/zoomout_disable"></item> <item android:drawable="@drawable/zoomout_normal"></item> </selector>layout/main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" > <com.baidu.mapapi.map.MapView android:id="@+id/bmapsView" android:layout_width="fill_parent" android:layout_height="fill_parent" android:clickable="true" /> <com.lzugis.myview.ZoomControlView android:id="@+id/ZoomControlView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_marginBottom="15.0dip" android:layout_marginRight="15.0dip"/> <com.lzugis.myview.SearchControlView android:id="@+id/SearchControlView" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_marginTop="15.0dip"/> <Button android:id="@+id/currentloc" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentBottom="true" android:layout_marginLeft="15.0dip" android:layout_marginBottom="50.0dip" android:background="@drawable/location_selector" /> </RelativeLayout>search_controls_layout.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" > <EditText android:id="@+id/edittextSearch" android:layout_width="fill_parent" android:layout_height="49dip" android:ems="10" > </EditText> <Button android:id="@+id/search" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_alignParentRight="true" android:layout_marginTop="3.0dip" android:layout_marginRight="3.0dip" android:background="@drawable/search_selector" /> </RelativeLayout>zoom_controls_layout.xml
<?xml version="1.0" encoding="UTF-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_alignWithParentIfMissing="true" android:layout_width="wrap_content" android:layout_height="wrap_content" > <Button android:id="@+id/zoomin" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/zoomin_seletor" /> <Button android:id="@+id/zoomout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/zoomin" android:background="@drawable/zoomout_seletor" /> </RelativeLayout>menu/main.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/menu_settings" android:icon="@drawable/setting" android:orderInCategory="100" android:title="設置"/> <item android:id="@+id/menu_exit" android:icon="@drawable/exit" android:orderInCategory="101" android:title="退出"/> </menu>
附件:
源代碼