使用SVG打造一个可以交互的地图

使用SVG打造一个可以交互的地图

首先还是看看效果

使用SVG打造一个可以交互的地图_第1张图片
宝岛台湾
交互感觉好像简单,但是这个地图怎么绘制呢?
  • 思路:
    • 利用Xml解析SVG的代码 封装成javaBean 最重要的得到Path
    • 重写OnDraw方法 利用Path绘制台湾地图
    • 重写OnTouchEvent方法,记录手指触摸位置,判断这个位置是否坐落在某个省份上
  • SVG地图
    使用SVG打造一个可以交互的地图_第2张图片
    在drawable中预览

    提示vector下有很多path,一个path对应地图上面一个小块,具体见文章结尾项目

台湾对应的SVG的代码太长,这里就不贴了,这里只做思路解析,文章结尾给出同性交友链接,喜欢就Star,fork

具体步骤
  • 1.创建一个对象用来保存path路径,这里使用了面向对象的思想,让对象自己处理逻辑和绘制
public class PathItem {
    private Path mPath;
    private boolean isSelect;

    public PathItem(Path path) {
        mPath = path;
    }

    /**
     * 是否touch在该path内部
     * @param x
     * @param y
     * @return
     */
    public boolean isTouch(int x, int y) {
       
    }

    public void draw(Canvas canvas, Paint paint) {
      
    }

    public PathItem setSelect(boolean select) {
        isSelect = select;
        return this;
    }
}
  • 2.解析SVG,解析比较耗时,这里开起一个线程解析,下面用到了一个解析path的工具类,在项目中可以找到
 /**
     * 解析path
     */
    private void parserPaths() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                // 创建DOM工厂对象
                DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
                try {
                    // DocumentBuilder对象
                    DocumentBuilder db = dbf.newDocumentBuilder();
                    //打开输入流
                    InputStream is = getResources().openRawResource(R.raw.taiwan_maps);
                    // 获取文档对象
                    Document doc = db.parse(is);
                    //获取path元素节点集合
                    NodeList paths = doc.getElementsByTagName("path");
                    PathItem item;
                    for (int i = 0; i < paths.getLength(); i++) {
                        // 取出每一个元素
                        Element personNode = (Element) paths.item(i);
                        //得到android:pathData属性值
                        String nodeValue = personNode.getAttribute("android:pathData");
                        //解析,并创建pathItem
                        item=new PathItem(PathParser.createPathFromPathData(nodeValue));
                        pathItems.add(item);//保存到pathItems集合里
                    }
                    Log.e(TAG, "蜗牛   itemsCount  " + pathItems.size());
                } catch (Exception e) {
                    Log.e(TAG, "蜗牛   解析出错 " );
                }
            }
        }).start();
        postInvalidate();
    }
  • 3.绘制
    • 在pathItem里实现draw()方法
 public void draw(Canvas canvas, Paint paint) {
        if (isSelect) {
            //首先绘制选中的背景阴影
            paint.clearShadowLayer();
            paint.setStyle(Paint.Style.FILL);
            paint.setShadowLayer(8, 0, 0, Color.BLACK);
            canvas.drawPath(mPath,paint);
            //绘制具体显示的
            paint.clearShadowLayer();
            paint.setColor(Color.BLUE);
            paint.setStyle(Paint.Style.FILL);
            canvas.drawPath(mPath,paint);
        } else {
            //绘制具体显示的
            paint.clearShadowLayer();
            paint.setColor(Color.GRAY);
            paint.setStyle(Paint.Style.FILL);
            canvas.drawPath(mPath,paint);
        }
    }
  • 调用item的draw方法
 @Override
    protected void onDraw(Canvas canvas) {
        canvas.save();
        canvas.scale(scale,scale);
        for (PathItem pathItem : pathItems) {
            pathItem.draw(canvas,mPaint);
        }
        canvas.restore();
    }

不出意外走到这里就可以在界面绘制出地图了,接下来处理交互

  • 4.交互
    • 实现PathItem的isTouch方法
 /**
     * 是否touch在该path内部
     * @param x
     * @param y
     * @return
     */
    public boolean isTouch(int x, int y) {
        Region result = new Region();
        //构造一个区域对象。
        RectF r=new RectF();
        //计算path的边界
        mPath.computeBounds(r, true);
        //设置区域路径和剪辑描述的区域
        result.setPath(mPath, new Region((int)r.left,(int)r.top,(int)r.right,(int)r.bottom));
        return result.contains(x, y);
    }
  • 在自定义mapview里面调用isTouch方法
 mDetector=new GestureDetector(new GestureDetector.SimpleOnGestureListener(){
            @Override
            public boolean onDown(MotionEvent e) {
                float x = e.getX()/scale;
                float y = e.getY()/scale;
                for (PathItem pathItem : pathItems) {
                    if (pathItem.isTouch((int) x, (int) y)){
                        pathItem.setSelect(true);
                    }else {
                        pathItem.setSelect(false);
                    }
                }
                invalidate();
                return true;
            }
        });

这里就完成了所有工作了,代码就不具体贴了,链接SVGMapVIew,喜欢就star哦

你可能感兴趣的:(使用SVG打造一个可以交互的地图)