使用SVG打造一个可以交互的地图
首先还是看看效果
交互感觉好像简单,但是这个地图怎么绘制呢?
- 思路:
- 利用Xml解析SVG的代码 封装成javaBean 最重要的得到Path
- 重写OnDraw方法 利用Path绘制台湾地图
- 重写OnTouchEvent方法,记录手指触摸位置,判断这个位置是否坐落在某个省份上
- SVG地图
提示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哦