有钱人咱就不说了,因为偶是个穷银……因为穷,所以去年买的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("\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
<?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>