财富坊cff888
  • 删除
  • ? ? ? 在我们进行地图相关开发时候,避免不了要绘制比例尺。在百度,高德的地图API里都提供了比例尺控件,但是ArcGIS for Android里并没有提供。不过没关系,我们可以自己绘制一个比例尺来。


    ? ? ? 在绘制比例尺前,我们先了解几个概念:


    1. PPI,Pixels Per Inch的所写,表示的是每英寸所拥有的像素数目;
    2. PX,像素,表示图像中的一个最小单位;
    3. DPI,Dots Per Inch,每英寸点数,即图像密度;
    4. .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,然后比例尺的长度根据实际长度会做一定伸缩。这里我采用第二种,因为第一种根据实际比例往往比例尺的比值不是整数,并且在较大比例时候显示位数较长,四舍五入又会失去精度。


    ? ? ? 最后,是监听地图放大缩小事件,并作出响应改变比例尺。


    ? ? ? 方法就是这么简单,那就实际开动吧。


    第一步,实例化地图,加载图层:

    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:

    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的参数:

    private void initVariables(){
        scaleWidth=104;//
        scaleHeight=8;//比比例尺宽度例尺高度
        textColor= Color.BLACK;//比例尺字体颜色
        text="20公里";//比例尺文本
        textSize=18;//比例尺宽度
        scaleSpaceText=8;//比例尺文本与图形的间隔高度
        mPaint = new Paint();//画笔
    }


    ? ? ? 重写onMearsure()方法:

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthSize = getWidthSize(widthMeasureSpec);
        int heightSize = getHeightSize(heightMeasureSpec);
        setMeasuredDimension(widthSize, heightSize);
    }


    ? ? ? 获取自定义View的宽和高:

    **
     * 测量ScaleView的宽度
     * @param widthMeasureSpec
     * @return
     */
    private int getWidthSize(int widthMeasureSpec){
        return MeasureSpec.getSize(widthMeasureSpec);
    }
    
    /**
     * 测量ScaleView的高度
     * @param heightMeasureSpec
     * @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;
    }


    ? ? ? 重写onDraw()方法,绘制比例尺:

    **
     * 绘制上面的文字和下面的比例尺,因为比例尺是.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图片:

    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的进制选取了比例尺的单位:

    public void refreshScaleView() {
            if(mapView == null){
                throw new NullPointerException("you can call setMapView(MapView mapView) at first");
            }
            double scale=this.mapView.getScale()/100;//结果单位米,表示图上1厘米代表*米
            double ppi=getPPIOfDevice();
            if(scale>0&&scale<=20){//换算20米
                String unit = "20米";
                int scaleWidth=(int)(20*264/2.54/scale);//264为ppi,264/2.54为1厘米的像素数
                setText(unit);//更新文字
                setScaleWidth(scaleWidth);//更新比例尺长度
            }else if(scale>20&&scale<=50){//换算50米
                String unit = "50米";
                int scaleWidth=(int)(50*264/2.54/scale);
                setText(unit);//更新文字
                setScaleWidth(scaleWidth);//更新比例尺长度
            }else if(scale>50&&scale<=100){//换算20米
                String unit = "100米";
                int scaleWidth=(int)(100*264/2.54/scale);
                setText(unit);//更新文字
                setScaleWidth(scaleWidth);//更新比例尺长度
            }else if(scale>100&&scale<=200){//换算20米
                String unit = "200米";
                int scaleWidth=(int)(200*264/2.54/scale);
                setText(unit);//更新文字
                setScaleWidth(scaleWidth);//更新比例尺长度
            }else if(scale>200&&scale<=500){//换算20米
                String unit = "500米";
                int scaleWidth=(int)(500*264/2.54/scale);
                setText(unit);//更新文字
                setScaleWidth(scaleWidth);//更新比例尺长度
            }else if(scale>500&&scale<=1000){//换算20米
                String unit = "1公里";
                int scaleWidth=(int)(1000*264/2.54/scale);
                setText(unit);//更新文字
                setScaleWidth(scaleWidth);//更新比例尺长度
            }else if(scale>1000&&scale<=2000){//换算20米
                String unit = "2公里";
                int scaleWidth=(int)(2000*264/2.54/scale);
                setText(unit);//更新文字
                setScaleWidth(scaleWidth);//更新比例尺长度
            }else if(scale>2000&&scale<=5000){//换算20米
                String unit = "5公里";
                int scaleWidth=(int)(5000*264/2.54/scale);
                setText(unit);//更新文字
                setScaleWidth(scaleWidth);//更新比例尺长度
            }else if(scale>5000&&scale<=10000){//换算20米
                String unit = "10公里";
                int scaleWidth=(int)(10000*264/2.54/scale);
                setText(unit);//更新文字
                setScaleWidth(scaleWidth);//更新比例尺长度
            }else if(scale>10000&&scale<=20000){//换算20米
                String unit = "20公里";
                int scaleWidth=(int)(20000*264/2.54/scale);
                setText(unit);//更新文字
                setScaleWidth(scaleWidth);//更新比例尺长度
            }else if(scale>20000&&scale<=25000){//换算20米
                String unit = "25公里";
                int scaleWidth=(int)(25000*264/2.54/scale);
                setText(unit);//更新文字
                setScaleWidth(scaleWidth);//更新比例尺长度
            }else if(scale>25000&&scale<=50000){//换算20米
                String unit = "50公里";
                int scaleWidth=(int)(50000*264/2.54/scale);
                setText(unit);//更新文字
                setScaleWidth(scaleWidth);//更新比例尺长度
            }else if(scale>50000&&scale<=100000){//换算20米
                String unit = "100公里";
                int scaleWidth=(int)(100000*264/2.54/scale);
                setText(unit);//更新文字
                setScaleWidth(scaleWidth);//更新比例尺长度
            }else if(scale>100000&&scale<=200000){//换算20米
                String unit = "200公里";
                int scaleWidth=(int)(200000*264/2.54/scale);
                setText(unit);//更新文字
                setScaleWidth(scaleWidth);//更新比例尺长度
            }else if(scale>200000&&scale<=250000){//换算20米
                String unit = "250公里";
                int scaleWidth=(int)(250000*264/2.54/scale);
                setText(unit);//更新文字
                setScaleWidth(scaleWidth);//更新比例尺长度
            }else if(scale>250000&&scale<=500000){//换算20米
                String unit = "500公里";
                int scaleWidth=(int)(500000*264/2.54/scale);
                setText(unit);//更新文字
                setScaleWidth(scaleWidth);//更新比例尺长度
            }else if(scale>500000&&scale<=scale){//换算20米
                String unit = "1000公里";
                int scaleWidth=(int)(1000000*264/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:

    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;
    }


    第三步:写响应事件


    ? ? ? 在ArcGIS的MapView有个监听地图大小变化的方法,叫setOnZoomListener(),在里面写响应事件即可:

    mMapView.setOnZoomListener(new OnZoomListener() {
        @Override
        public void preAction(float v, float v1, double v2) {
            //todo
        }
    
        @Override
        public void postAction(float v, float v1, double v2) {
            mMapScaleView.refreshScaleView();
        }
    });


    ? ? ? 效果图如下:







    阅读全文
    版权声明:本文为博主原创文章,未经博主允许不得转载。

    ArcGIS Server 自定义比例尺切图

    1、用ArcMap随意打开一份需要进行发布的.mxd地图文件,此处我以北京市为例,在Catalog面板中展开GIS Servers节点,此时可以看见ArcGIS Server的服务处于未连接状态,我们...
    • SmileCoffin
    • SmileCoffin
    • 2017年06月01日 09:38
    • 1207

    Arcgis for Android解决定位结果与地图偏移的简单处理思维

    Arcgis for Android解决定位结果与地图偏移的简单处理思维
    • GISShiXiSheng
    • GISShiXiSheng
    • 2014年12月25日 10:26
    • 2838

    ArcGIS For Android 定位绘图工具 [中心点,误差圆]

    /** * 定位绘图 * * @author wuxin * @time 10:29 */public class DrawLocate {private static Graphic graphic...
    • u014014578
    • u014014578
    • 2014年07月01日 11:12
    • 2289

    ArcGIS读取天地图出现错位的情况

    天地图2.0(http://www.chinaonmap.com)于2013年3月份上线,基本情况如下: 1)?????基于OGC的WMTS 1.0.0版本; 2)?????提供矢量地图、影像地图...
    • u010499087
    • u010499087
    • 2017年01月23日 09:40
    • 2648

    ArcGIS For Android 地图比例尺获取

    mMapView.setOnZoomListener(new OnZoomListener() { ??? ???@Override ???public void preAction(float...
    • u014014578
    • u014014578
    • 2014年05月23日 10:49
    • 2625

    Arcgis For Android实现比例尺

    argic for android实现比例尺,没有相关图层Api,所以界面显示只能自己实现,以下是计算方法:public void getScaleText(double scale) { s...
    • canney_chen
    • canney_chen
    • 2015年09月17日 19:02
    • 2082

    android自定义view之地图(一)

    最近参加了一个比赛,要用到自己做一个自定义的小地图,所以在网上查找了一些关于自定义view的有关资料,也了解了自定义控件的初步知识。效果图 第一阶段我画了一个自制的网格图,点哪个网格就会哪个网格就会...
    • qq_25673113
    • qq_25673113
    • 2016年04月26日 21:36
    • 861

    自定义ImageView实现地图(一)

    一个用imageview实现地图功能的方法
    • a287574014
    • a287574014
    • 2016年01月30日 16:28
    • 1150

    Android 自定义地图控件,可放大缩小拖动,加点加线

    • 2016年08月23日 15:28
    • 24.21MB
    • 下载

    Android 自定义 地图 室内

    在Android程序中开发一个自定义地图的思路。 Android--UI之ImageView http://www.cnblogs.com/plokmju/p/3212558.ht...
    • YorkCai
    • YorkCai
    • 2014年03月01日 19:13
    • 6817
    内容举报
    返回顶部
    收藏助手
    不良信息举报
    您举报文章:ArcGIS for Android 自定义地图比例尺
    举报原因:
    原因补充:

    (最多只允许输入30个字)