使用SVG打造可交互的自定义地图

来源:互联网 发布:梧桐一叶落而天下知秋 编辑:程序博客网 时间:2024/06/04 20:03

最近发现了一个好玩的东西:SVG,秉承着学以致用的原则,做了一个小demo。
先上效果图:
这里写图片描述

这是一个可以交互的中国地图.

像这类复杂的自定义空间,如果要我们自己来画,我估计会让我开始怀疑人生吧!

好了 废话不多说,下面我们就用svg的方式来实现这个自定义的地图控件:
步骤:
1:下载中国地图的svg文件
2:然后将svg文件转换成android能用的xml文件:附上链接一个:http://inloop.github.io/svg2android/
3:由于步骤2解析到的SVG是xml格式的,如果说不做交互的话,可以直接显示(可改变源文件的颜色),如果要做交互的话,就需要获取到每一个省对应的path,然后设置交互点击事件了,这样的话,就需要解析得到我们需要的path。
4:解析完之后,就需要将每一个path会知道canvas中去
5:设置点击事件,判断当前点击的是哪个省份

这里1,2步就直接略过了,我们从第三步开始:

//开启一个线程,用于解析xml文件private Thread parseSvgThread = new Thread(new Runnable() {        @Override        public void run() {            InputStream inputStream = mContext.getResources().openRawResource(R.raw.china);            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();            DocumentBuilder builder = null;            try {                builder = factory.newDocumentBuilder();                Document doc = builder.parse(inputStream);                Element rootElements = doc.getDocumentElement();                //解析path节点                NodeList items = rootElements.getElementsByTagName("path");                for(int i = 0;i<items.getLength();i++){                    Element element = (Element) items.item(i);                    String pathData = element.getAttribute("android:pathData");                    Path path = PathParser.createPathFromPathData(pathData);                    //将解析的每一条path创建一个javabean,然后放到容器中                    Province province = new Province(path);                    itemLists.add(province);                }                //解析完成之后,发送handler 通知解析完成并设置颜色                mHandler.sendEmptyMessage(0);            } catch (Exception e) {                e.printStackTrace();            }        }    });    Handler mHandler = new Handler() {        @Override        public void handleMessage(Message msg) {            if(itemLists != null && itemLists.size() > 0){                int size = itemLists.size();                for(int i = 0;i<size;i++){                    //简单设置下颜色itemLists.get(i).setDrawColor(colors[i%colors.length]);                }                //更新绘制                invalidate();            }        }    };

由于解析过程比较耗时,所以我们开启一个独立的线程来解析,解析完成之后通过handler来设置每一个省的颜色,然后更新绘制

第四步:

@Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        //1:画选择的        //2画没别选择的        if(itemLists != null && itemLists.size()>0){            canvas.save();            canvas.scale(scale,scale);            if(mSelectedItem != null){                mSelectedItem.drawableProvince(mPaint,canvas,true);            }            for(int i = 0;i<itemLists.size();i++){                if(itemLists.get(i) != mSelectedItem){                    itemLists.get(i).drawableProvince(mPaint,canvas,false);                }            }            canvas.restore();        }    }

然后在province的bean中,我们来做绘画的操作:

//在画板上画    public void drawableProvince(Paint paint, Canvas canvas,boolean isSelected){        if(isSelected){            //当前被选择的省            //画阴影            paint.setStyle(Paint.Style.FILL);            paint.setStrokeWidth(2);            paint.setColor(Color.BLACK);            paint.setShadowLayer(8,0,0,0xffffff);            canvas.drawPath(path,paint);            //画填充部分            paint.clearShadowLayer();            paint.setColor(Color.RED);            canvas.drawPath(path,paint);        }else{            //画填充部分            paint.setColor(drawColor);            paint.setStyle(Paint.Style.FILL);            paint.setStrokeWidth(1);            canvas.drawPath(path,paint);            paint.setStyle(Paint.Style.STROKE);            paint.setColor(0xFFD0E8F4);            canvas.drawPath(path,paint);        }    }

到这里,地图就可以按照我们自定义的颜色来显示了。
最后一步,设置监听,首先,我们在prvoince这个bean中,写一个方法,来判断当前点击的这个点是否在province中:

//判断某一点是否包含在该省内    public boolean isContain(int x,int y){        RectF rectF = new RectF();        path.computeBounds(rectF,true);        Region region = new Region();        region.setPath(path,new Region((int)rectF.left,(int)rectF.top,(int)rectF.right,(int) rectF.bottom));        return region.contains(x,y);    }

这里使用的方法是:创建一个包含path的区域(region),然后使用region的contains方法来进行判断。

最后,我们只需要在mapview中来处理touch事件并刷新ui就可以了。

原创粉丝点击