有钱人咱就不说了,因为偶是个穷银……因为穷,所以去年买的Huawei C8650+到现在还在上岗,对于没有钱买好的配置的手机的童鞋来说,类似于百度,谷歌,高德等商家的地图在自己的机器上跑起来确实是有点勉为其难,为了能够用上手机的地图,并不怎么大,最近闲来无事,就动起了这方面的脑筋,结果就是用百度地图API开发一个自己想要的功能的地图……
这是经过一点时间倒腾后的一点点小成果,实现了自定义的放大缩小按钮,GPS定位,GPS当前位置500m范围内关键字的搜索。下面这张截图说明了上面提到的几个功能,其中我的搜索关键字为“公交”……
嗯,看完效果说说我的具体实现吧。下图为工程的目录结构:
源代码如下:
MainActivity.java
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(" error code : "); sb.append(location.getLocType()); sb.append(" latitude : "); sb.append(location.getLatitude()); sb.append(" lontitude : "); sb.append(location.getLongitude()); sb.append(" radius : "); sb.append(location.getRadius()); if (location.getLocType() == BDLocation.TypeGpsLocation) { sb.append(" speed : "); sb.append(location.getSpeed()); sb.append(" satellite : "); sb.append(location.getSatelliteNumber()); } else if (location.getLocType() == BDLocation.TypeNetWorkLocation) { sb.append(" addr : "); 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
<?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
<?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>
附件:
源代码