在我们进行地图相关开发时候,避免不了要绘制比例尺。在百度,高德的地图API里都提供了比例尺控件,但是ArcGIS for Android里并没有提供。不过没关系,我们可以自己绘制一个比例尺来。
 
      在绘制比例尺前,我们先了解几个概念:
 
 
- PPI,Pixels Per Inch的所写,表示的是每英寸所拥有的像素数目;
- PX,像素,表示图像中的一个最小单位;
- DPI,Dots Per Inch,每英寸点数,即图像密度;
- .9.PNG,Android开发里面的一种特殊的图片,这种格式的图片通过ADT自带的编辑工具生成,使用九宫格切分的方法,使图片支持在Android环境下的自适应展示。即这种类型图片在Android里无论怎样拉伸缩小都不失真。
 
 
      其中PPI和DPI在实际生活中的定义是不太一样的,而在Android里,他们的含义却是相似的。单独把DPI拿出来主要是Android里有个方法可以分别获取到屏幕X轴和Y轴的像素密度。
 
      .9.PNG格式的图片不失真,正好适合我们做来做比例尺图片。
 
       好了,我们好绘制一个比例尺,需要做些什么呢?
 
       首先,我们得知道当前地图比例,这个参数可以通过MapView.getScale来获取;
 
       其次,我们要根据当前地图比例绘制一个比例尺。绘制的方案有两种,一个是固定尺子长度,根据当前地图比例更换比例尺的比,比如1:2000,1:3000等;另一种是固定一些比例单位,比如1:50000后就是1:20000,然后比例尺的长度根据实际长度会做一定伸缩。这里我采用第二种,因为第一种根据实际比例往往比例尺的比值不是整数,并且在较大比例时候显示位数较长,四舍五入又会失去精度。
 
      最后,是监听地图放大缩小事件,并作出响应改变比例尺。
 
      方法就是这么简单,那就实际开动吧。
 
第一步,实例化地图,加载图层:
 
[java] view plain
class="tracking-ad" data-mod="popu_168"> copy
 
- mMapView=(MapView)findViewById(R.id.mapview);  
- mMapScaleView=(MapScaleView)findViewById(R.id.scaleView);  
- String path= StorageUtil.getSDCardRootPath(getApplicationContext());  
- ArcGISLocalTiledLayer layer=new ArcGISLocalTiledLayer(path);  
- mMapView.addLayer(layer,0);  
- mMapScaleView.setMapView(mMapView);  
- ArcGISRuntime.setClientId(System.clint);
- mMapView.setMapBackground(0xFAFAFA, 0xffffff, 0.0f, 0.0f);
 
 
第二步,自定义View,绘制比例尺:
      
      初始化自定义View:
 
[java] view plain
 copy
 
- public MapScaleView(Context context) {  
-     this(context, null);  
-     this.context=context;  
-     this.initVariables();  
- }  
-   
- public MapScaleView(Context context, AttributeSet attrs) {  
-     this(context, attrs, 0);  
-     this.context=context;  
-     this.initVariables();  
- }  
-   
- public MapScaleView(Context context, AttributeSet attrs, int defStyle) {  
-     super(context, attrs, defStyle);  
-     this.context=context;  
-     this.initVariables();  
- }  
 
 
      初始化自定义View的参数:
 
[java] view plain
 copy
 
- private void initVariables(){  
-     scaleWidth=104;
-     scaleHeight=8;
-     textColor= Color.BLACK;
-     text="20公里";
-     textSize=18;
-     scaleSpaceText=8;
-     mPaint = new Paint();
- }  
 
 
      重写onMearsure()方法:
 
[java] view plain
 copy
 
- @Override  
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
-     super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
-     int widthSize = getWidthSize(widthMeasureSpec);  
-     int heightSize = getHeightSize(heightMeasureSpec);  
-     setMeasuredDimension(widthSize, heightSize);  
- }  
 
 
      获取自定义View的宽和高:
 
[java] view plain
 copy
 
- **  
-  * 测量ScaleView的宽度  
-  * @param widthMeasureSpec  
-  * @return  
-  */  
- private int getWidthSize(int widthMeasureSpec){  
-     return MeasureSpec.getSize(widthMeasureSpec);  
- }  
-   
- 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;  
- }  
 
 
      重写onDraw()方法,绘制比例尺:
 
[java] view plain
 copy
 
- **  
-  * 绘制上面的文字和下面的比例尺,因为比例尺是.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, width, textSize + scaleSpaceText + scaleHeight);  
-     drawNinepath(canvas, R.drawable.icon_scale, scaleRect);  
- }  
 
 
      绘制.9.PNG图片:
 
[java] view plain
 copy
 
- 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);  
- }  
 
 
      接下来就是根据获取的地图比例,绘制比例尺,更新比例尺的单位以及绘制它的长度,这里我按照2、5、1的进制选取了比例尺的单位:
 
[java] view plain
 copy
 
- public void refreshScaleView() {  
-     if(mapView == null){  
-         throw new NullPointerException("you can call setMapView(MapView mapView) at first");  
-     }  
-     double scale=this.mapView.getScale()/100;
-     double ppi=getPPIOfDevice();  
-     if(scale>0&&scale<=20){
-         String unit = "20米";  
-         int scaleWidth=(int)(20*ppi/2.54/scale);
-         setText(unit);
-         setScaleWidth(scaleWidth);
-     }else if(scale>20&&scale<=50){
-         String unit = "50米";  
-         int scaleWidth=(int)(50*ppi/2.54/scale);  
-         setText(unit);
-         setScaleWidth(scaleWidth);
-     }else if(scale>50&&scale<=100){
-         String unit = "100米";  
-         int scaleWidth=(int)(100*ppi/2.54/scale);  
-         setText(unit);
-         setScaleWidth(scaleWidth);
-     }else if(scale>100&&scale<=200){
-         String unit = "200米";  
-         int scaleWidth=(int)(200*ppi/2.54/scale);  
-         setText(unit);
-         setScaleWidth(scaleWidth);
-     }else if(scale>200&&scale<=500){
-         String unit = "500米";  
-         int scaleWidth=(int)(500*ppi/2.54/scale);  
-         setText(unit);
-         setScaleWidth(scaleWidth);
-     }else if(scale>500&&scale<=1000){
-         String unit = "1公里";  
-         int scaleWidth=(int)(1000*ppi/2.54/scale);  
-         setText(unit);
-         setScaleWidth(scaleWidth);
-     }else if(scale>1000&&scale<=2000){
-         String unit = "2公里";  
-         int scaleWidth=(int)(2000*ppi/2.54/scale);  
-         setText(unit);
-         setScaleWidth(scaleWidth);
-     }else if(scale>2000&&scale<=5000){
-         String unit = "5公里";  
-         int scaleWidth=(int)(5000*ppi/2.54/scale);  
-         setText(unit);
-         setScaleWidth(scaleWidth);
-     }else if(scale>5000&&scale<=10000){
-         String unit = "10公里";  
-         int scaleWidth=(int)(10000*ppi/2.54/scale);  
-         setText(unit);
-         setScaleWidth(scaleWidth);
-     }else if(scale>10000&&scale<=20000){
-         String unit = "20公里";  
-         int scaleWidth=(int)(20000*ppi/2.54/scale);  
-         setText(unit);
-         setScaleWidth(scaleWidth);
-     }else if(scale>20000&&scale<=25000){
-         String unit = "25公里";  
-         int scaleWidth=(int)(25000*ppi/2.54/scale);  
-         setText(unit);
-         setScaleWidth(scaleWidth);
-     }else if(scale>25000&&scale<=50000){
-         String unit = "50公里";  
-         int scaleWidth=(int)(50000*ppi/2.54/scale);  
-         setText(unit);
-         setScaleWidth(scaleWidth);
-     }else if(scale>50000&&scale<=100000){
-         String unit = "100公里";  
-         int scaleWidth=(int)(100000*ppi/2.54/scale);  
-         setText(unit);
-         setScaleWidth(scaleWidth);
-     }else if(scale>100000&&scale<=200000){
-         String unit = "200公里";  
-         int scaleWidth=(int)(200000*ppi/2.54/scale);  
-         setText(unit);
-         setScaleWidth(scaleWidth);
-     }else if(scale>200000&&scale<=250000){
-         String unit = "250公里";  
-         int scaleWidth=(int)(250000*ppi/2.54/scale);  
-         setText(unit);
-         setScaleWidth(scaleWidth);
-     }else if(scale>250000&&scale<=500000){
-         String unit = "500公里";  
-         int scaleWidth=(int)(500000*ppi/2.54/scale);  
-         setText(unit);
-         setScaleWidth(scaleWidth);
-     }else if(scale>500000&&scale<=1000000){
-         String unit = "1000公里";  
-         int scaleWidth=(int)(1000000*ppi/2.54/scale);  
-         setText(unit);
-         setScaleWidth(scaleWidth);
-     }  
-   
-     invalidate();  
- }  
 
 
      其中,获取屏幕PPI的方法如下:首先是用android.view包下的Display类里的getRealSize()方法获取屏幕分辨率;其次是用android.util包下有个DisplayMetrics类来获取密度相关的信息,该类里的xdpi和ydpi参数分别表示屏幕X轴和Y轴的点数密度,用X轴和Y轴的像素除以密度得到X轴和Y轴的真实长度,进而求得屏幕对角线的真实长度;最后用屏幕对角线的像素点数除以屏幕对角线的真实长度,得到屏幕的PPI:
 
[java] view plain
 copy
 
- private double getPPIOfDevice() {  
-     Point point = new Point();  
-     Activity activity=(Activity) context;  
-     activity.getWindowManager().getDefaultDisplay().getRealSize(point);
-     DisplayMetrics dm = getResources().getDisplayMetrics();  
-     double x = Math.pow(point.x/ dm.xdpi, 2);
-     double y = Math.pow(point.y / dm.ydpi, 2);  
-     double screenInches = Math.sqrt(x + y);  
-     Double ppi=Math.sqrt(Math.pow(point.x, 2)+Math.pow(point.y, 2))/screenInches;  
-     return ppi;  
- }  
 源码免费下载地址:http://www.jinhusns.com/Products/Download
 
第三步:写响应事件
 
 
      在ArcGIS的MapView有个监听地图大小变化的方法,叫setOnZoomListener(),在里面写响应事件即可:
 
[java] view plain
 copy
 
- mMapView.setOnZoomListener(new OnZoomListener() {  
-     @Override  
-     public void preAction(float v, float v1, double v2) {  
-         
-     }  
-   
-     @Override  
-     public void postAction(float v, float v1, double v2) {  
-         mMapScaleView.refreshScaleView();  
-     }  
- });  
 
      效果图如下:
 
