当前位置: 代码迷 >> Android >> Android 百度map开发(三)- 实现比例尺功能和替换自带的缩放组件
  详细解决方案

Android 百度map开发(三)- 实现比例尺功能和替换自带的缩放组件

热度:71   发布时间:2016-04-28 08:04:59.0
Android 百度地图开发(三)--- 实现比例尺功能和替换自带的缩放组件

转载请注明出处:http://blog.csdn.net/xiaanming/article/details/11821523


貌似有些天没有写博客了,前段时间在忙找工作的事,面试了几家公司,表示反响还不错,过完国庆节去新公司报道,期待新的公司,新的同事,而且新公司还有很多女孩子,哈哈,我可是一年多没和女孩子一起工作过了,之前的公司全是男的,你没听错,真的全是男的,我还以为我自己不会在爱了,现在Android市场还可以,想要跳槽换工作的赶紧,过了这个村就没这个店了,还有就是恭喜自己成了博客专家了,很开心也很感谢CSDN给我这份荣誉,我会继续写出对大家有用的博文,感谢大家的支持,今天继续给大家带来百度地图开发系列三 ,实现比例尺功能和替换自带的缩放组件,先看下项目工程结构


ScaleView是比例尺控件,ZoomControlView是缩放控件,MainActivity就是我们的主界面了


先看下ZoomControlView类,代码如下

package com.example.baidumapdemo;import com.baidu.mapapi.map.MapView;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);		}	}}


这个类封装好了地图的缩放功能,里面主要是两个按钮,一个按钮是放大MapView,当放大到了MapView的最大缩放级别,设置此按钮的Enable为false,另一个按钮缩小MapView,当缩小到了MapView最小的缩放级别,设置此按钮的Enable为false,refreshZoomButtonStatus()方法就是实现了此功能,我们根据MapView的缩放级别来更新按钮的状态,我们还必须调用setMapView(MapView mapView)方法来设置ZoomControlView与MapView关联,ZoomControlView的布局文件zoom_controls_layout我就不贴出来了,里面就两个按钮,然后给按钮设置背景选择器seletor


ScaleView类的代码如下

package com.example.baidumapdemo;import com.baidu.mapapi.map.MapView;import com.baidu.platform.comapi.basestruct.GeoPoint;import android.annotation.SuppressLint;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.NinePatch;import android.graphics.Paint;import android.graphics.Rect;import android.graphics.Typeface;import android.util.AttributeSet;import android.view.View;public class ScaleView extends View {	private Paint mPaint;	/**	 * 比例尺的宽度	 */	private int scaleWidth;	/**	 * 比例尺的高度	 */	private int scaleHeight = 4;	/**	 * 比例尺上面字体的颜色	 */	private int textColor = Color.BLACK;	/**	 * 比例尺上边的字体	 */	private String text;	/**	 * 字体大小	 */	private int textSize = 16;	/**	 * 比例尺与字体间的距离	 */	private int scaleSpaceText = 8;	/**	 * 百度地图最大缩放级别	 */	private static final int MAX_LEVEL = 19;	/**	 * 各级比例尺分母值数组	 */	private static final int[] SCALES = {20, 50, 100, 200, 500, 1000, 2000,			5000, 10000, 20000, 25000, 50000, 100000, 200000, 500000, 1000000,			2000000 };	/**	 * 各级比例尺上面的文字数组	 */	private static final String[] SCALE_DESCS = { "20米", "50米", "100米", "200米",			"500米", "1公里", "2公里", "5公里", "10公里", "20公里", "25公里", "50公里",			"100公里", "200公里", "500公里", "1000公里", "2000公里" };		private MapView mapView;			/**	 * 与MapView设置关联	 * @param mapView	 */	public void setMapView(MapView mapView) {		this.mapView = mapView;	}	public ScaleView(Context context) {		this(context, null);	}		public ScaleView(Context context, AttributeSet attrs) {		this(context, attrs, 0);	}	public ScaleView(Context context, AttributeSet attrs, int defStyle) {		super(context, attrs, defStyle);		mPaint = new Paint();	}		/**	 * 绘制上面的文字和下面的比例尺,因为比例尺是.9.png,我们需要利用drawNinepath方法绘制比例尺	 */	@SuppressLint("DrawAllocation")	@Override	protected void onDraw(Canvas canvas) {		super.onDraw(canvas);				int width = scaleWidth;				mPaint.setColor(textColor);		mPaint.setAntiAlias(true);		mPaint.setTextSize(textSize);		mPaint.setTypeface(Typeface.DEFAULT_BOLD);		float textWidth = mPaint.measureText(text);				canvas.drawText(text, (width - textWidth) / 2, textSize, mPaint);				Rect scaleRect = new Rect(0, textSize + scaleSpaceText, scaleWidth, textSize + scaleSpaceText + scaleHeight);		drawNinepath(canvas, R.drawable.icon_scale, scaleRect);	}		/**	 * 手动绘制.9.png图片	 * @param canvas	 * @param resId	 * @param rect	 */	private void drawNinepath(Canvas canvas, int resId, Rect rect){          Bitmap bmp= BitmapFactory.decodeResource(getResources(), resId);          NinePatch patch = new NinePatch(bmp, bmp.getNinePatchChunk(), null);          patch.draw(canvas, rect);      }		/**	 * 测量ScaleView的方法,	 */	@Override	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {		super.onMeasure(widthMeasureSpec, heightMeasureSpec);		int widthSize = getWidthSize(widthMeasureSpec);		int heightSize = getHeightSize(heightMeasureSpec);		setMeasuredDimension(widthSize, heightSize);	}		/**	 * 测量ScaleView的宽度	 * @param widthMeasureSpec	 * @return	 */	private int getWidthSize(int widthMeasureSpec){		return MeasureSpec.getSize(widthMeasureSpec);	}		/**	 * 测量ScaleView的高度	 * @param widthMeasureSpec	 * @return	 */	private int getHeightSize(int heightMeasureSpec){		int mode = MeasureSpec.getMode(heightMeasureSpec);		int height = 0;		switch (mode) {		case MeasureSpec.AT_MOST:			height = textSize + scaleSpaceText + scaleHeight;			break;		case MeasureSpec.EXACTLY:{			height = MeasureSpec.getSize(heightMeasureSpec);			break;		}		case MeasureSpec.UNSPECIFIED:{			height = Math.max(textSize + scaleSpaceText + scaleHeight, MeasureSpec.getSize(heightMeasureSpec));			break;		}		}				return height;	}		/**	 * 根据缩放级别,得到对应比例尺在SCALES数组中的位置(索引)	 * @param zoomLevel	 * @return	 */	private static int getScaleIndex(int zoomLevel) {		return MAX_LEVEL - zoomLevel;	}	/**	 * 根据缩放级别,得到对应比例尺	 * 	 * @param zoomLevel	 * @return	 */	public static int getScale(int zoomLevel) {		return SCALES[getScaleIndex(zoomLevel)];	}	/**	 *  根据缩放级别,得到对应比例尺文字	 * @param zoomLevel	 * @return	 */	public static String getScaleDesc(int zoomLevel) {		return SCALE_DESCS[getScaleIndex(zoomLevel)];	}		/**	 * 根据地图当前中心位置的纬度,当前比例尺,得出比例尺图标应该显示多长(多少像素)	 * @param map	 * @param scale	 * @return	 */	public static int meterToPixels(MapView map, int scale) {		// 得到当前中心位置对象		GeoPoint geoPoint = map.getMapCenter();		// 得到当前中心位置纬度		double latitude = geoPoint.getLatitudeE6() / 1E6;		// 得到象素数,比如当前比例尺是1/10000,比如scale=10000,对应在该纬度应在地图中绘多少象素		// 参考http://rainbow702.iteye.com/blog/1124244		return (int) (map.getProjection().metersToEquatorPixels(scale) / (Math				.cos(Math.toRadians(latitude))));					}	/**	 * 设置比例尺的宽度	 * @param scaleWidth	 */	public  void setScaleWidth(int scaleWidth) {		this.scaleWidth = scaleWidth;	}	/**	 * 设置比例尺的上面的 text 例如 200公里	 * @param text	 */	private void setText(String text) {		this.text = text;	}	/**	 * 设置字体大小	 * @param textSize	 */	public void setTextSize(int textSize) {		this.textSize = textSize;		invalidate();	}			/**	 * 根据缩放级别更新ScaleView的文字以及比例尺的长度	 * @param level	 */	public void refreshScaleView(int level) {		if(mapView == null){			throw new NullPointerException("you can call setMapView(MapView mapView) at first");		}		setText(getScaleDesc(level));		setScaleWidth(meterToPixels(mapView, getScale(level)));		invalidate();	}}

ScaleView是比例尺控件类,主要是提供比例尺的绘制功能,在onDraw(Canvas canvas)的方法中绘制上面的距离和下面的比例尺长度,这里面要说下drawNinepath()方法,因为我们的比例尺图片是.9.png格式的,保证图片拉伸状态下不变形,如果用平常绘制一般图片的方法会报ClassCastException,所以我们可以利用drawNinepath()来手动绘制.9.png格式的图片,我们比例尺的长度是变化的,我们需要将以米为计量单位的距离(沿赤道)在当前缩放水平下转换到一个以像素(水平)为计量单位的距离,meterToPixels()方法根据我们MapView当前的缩放级别,得出比例尺图标应该显示多长,refreshScaleView()是用来更新ScaleView的,更新上面的字符串和下面比例尺的长度,当然我们也必须调用setMapView(MapView mapView)方法来设置ScaleView与MapView关联


接下来我们就来使用我们的比例尺控件和缩放控件了,先看下布局

<?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/bmapView"        android:layout_width="fill_parent"        android:layout_height="fill_parent"        android:clickable="true" />    <com.example.baidumapdemo.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="20.0dip"        android:layout_marginRight="5.0dip"/>    <com.example.baidumapdemo.ScaleView        android:id="@+id/scaleView"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentBottom="true"        android:layout_alignParentLeft="true"        android:layout_marginBottom="40dp"        android:layout_marginLeft="20dp" /></RelativeLayout>
主界面MainActivity的代码如下

package com.example.baidumapdemo;import android.app.Activity;import android.graphics.Bitmap;import android.os.Bundle;import android.widget.Toast;import com.baidu.mapapi.BMapManager;import com.baidu.mapapi.MKGeneralListener;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.platform.comapi.basestruct.GeoPoint;public class MainActivity extends Activity{	private BMapManager mBMapManager;	/**	 * MapView 是地图主控件	 */	private MapView mMapView = null;	/**	 * 用MapController完成地图控制	 */	private MapController mMapController = null;		private ScaleView mScaleView;	private ZoomControlView mZoomControlView;		@Override	protected void onCreate(Bundle savedInstanceState) {		super.onCreate(savedInstanceState);				//使用地图sdk前需先初始化BMapManager,这个必须在setContentView()先初始化		mBMapManager = new BMapManager(this);				//第一个参数是API key,		//第二个参数是常用事件监听,用来处理通常的网络错误,授权验证错误等,你也可以不添加这个回调接口		mBMapManager.init("CC61ac7527b65c95899608810873b173", new MKGeneralListener() {						//授权错误的时候调用的回调函数			@Override			public void onGetPermissionState(int iError) {				if (iError ==  MKEvent.ERROR_PERMISSION_DENIED) {					Toast.makeText(getApplication(), "API Key错误,请检查!",	                        Toast.LENGTH_LONG).show();	            }			}						//一些网络状态的错误处理回调函数			@Override			public void onGetNetworkState(int iError) {				if (iError == MKEvent.ERROR_NETWORK_CONNECT) {	                Toast.makeText(getApplication(), "您的网络出错啦!",	                    Toast.LENGTH_LONG).show();	            }			}		});				setContentView(R.layout.activity_main);		mMapView = (MapView) findViewById(R.id.bmapView);		//隐藏自带的地图缩放控件		mMapView.setBuiltInZoomControls(false);				mScaleView = (ScaleView) findViewById(R.id.scaleView);		mScaleView.setMapView(mMapView);		mZoomControlView = (ZoomControlView) findViewById(R.id.ZoomControlView);		mZoomControlView.setMapView(mMapView);						//地图显示事件监听器。 该接口监听地图显示事件,用户需要实现该接口以处理相应事件。		mMapView.regMapViewListener(mBMapManager, new MKMapViewListener() {						@Override			public void onMapMoveFinish() {				 refreshScaleAndZoomControl();			}						@Override			public void onMapLoadFinish() {							}												/**			 * 动画结束时会回调此消息.我们在此方法里面更新缩放按钮的状态			 */			@Override			public void onMapAnimationFinish() {				 refreshScaleAndZoomControl();			}						@Override			public void onGetCurrentMap(Bitmap arg0) {							}						@Override			public void onClickMapPoi(MapPoi arg0) {							}		});				//获取地图控制器        mMapController = mMapView.getController();        //设置地图是否响应点击事件  .        mMapController.enableClick(true);        //设置地图缩放级别        mMapController.setZoom(14);                refreshScaleAndZoomControl();                //保存精度和纬度的类,        GeoPoint p = new GeoPoint((int)(22.547923 * 1E6), (int)(114.067368 * 1E6));        //设置p地方为中心点        mMapController.setCenter(p);        	}			private void refreshScaleAndZoomControl(){        //更新缩放按钮的状态        mZoomControlView.refreshZoomButtonStatus(Math.round(mMapView.getZoomLevel()));        mScaleView.refreshScaleView(Math.round(mMapView.getZoomLevel()));	}			@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(mBMapManager != null){			mBMapManager.destroy();			mBMapManager = null;		}				super.onDestroy();			}}

主界面的代码还是比较简单的,主要是利用MapView的regMapViewListener()来注册地图显示事件监听器。 该接口监听地图显示事件,用户需要实现该接口以处理相应事件,分别在回调方法onMapAnimationFinish()和onMapMoveFinish()来更新ZoomControlView和ScaleView的一些状态

在运行之前需要在Manifest中加入相对应的权限问题

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />      <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />      <uses-permission android:name="android.permission.INTERNET" />      <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />      <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />      <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />      <uses-permission android:name="android.permission.READ_PHONE_STATE" />

运行结果



好了,今天的讲解到此结束,有疑问的朋友请在下面留言!


上面的代码有些东西没有贴出来,有兴趣的朋友可以下载源码项目源码,点击下载


2楼sinyu890807昨天 19:10
工作找好了?啥公司啊
Re: xiaanming昨天 19:11
回复sinyu890807n找好了,是一家物流公司
1楼jingdalu昨天 15:05
祝你工作顺利,加油。。。
Re: xiaanming昨天 18:11
回复jingdalun谢谢,你也一样
  相关解决方案