今天我们来攻克第二项——可交互式中国地图。
一开始我想用webview配合Echart来实现相应的效果,但奈何我json和html传值那一部分根本就没学,所以即使实现了效果也无法向其中传值……
所幸后来我又找到了一种新方法——SVG转XML绘图法
首先我们需要一个SVG文件,这里有个地图SVG的整合包,找到China就可以了
https://pan.baidu.com/s/1Z1E_hwG73IM39idcWoJx2w 提取码:e6br
因为这个SVG是转成xml格式,不需要额外导入包,所以这样咱们就算准备完全了
我们先找到chinaHigh.svg(low也行,但high分辨率高更细节)

然后访问这个网址:http://inloop.github.io/svg2android/,这是一个把SVG改组成xml的工具,只要把它拖进去就OK,非常便利

点击下载之后,把它放到咱们Android工程的app\src\main\res\raw下
之后先包装工具类:Chinaitem
public class chinaitem {
private Path path;
private int drawColor;
String name;
public chinaitem(Path path) {
this.path = path;
}
/**
* 绘制地图path
* @param canvas
* @param paint
* @param isSelect
*/
public void draw(Canvas canvas, Paint paint, boolean isSelect){
if(isSelect){
//画阴影图层
paint.setStrokeWidth(2);
paint.setShadowLayer(8,0,0,0xffffff);
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.BLACK);
canvas.drawPath(path,paint);
//画区域path
paint.clearShadowLayer();
paint.setStrokeWidth(2);
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.parseColor("#FBED6C"));
canvas.drawPath(path,paint);
}else{
//画线条
paint.clearShadowLayer();
paint.setStrokeWidth(1);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(0xFFD0E8F4);
canvas.drawPath(path,paint);
//画区域
paint.setStrokeWidth(2);
paint.setStyle(Paint.Style.FILL);
paint.setColor(drawColor);
canvas.drawPath(path,paint);
}
}
/**
* 判断当前点击坐标是否在path范围内
* @param x
* @param y
* @return
*/
public boolean isTouch(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));//判断X,Y是否在region区域范围内
if(region.contains(x,y)) return true;
return false;
}
public void setDrawColor(int drawColor) {
this.drawColor = drawColor;
}
}
编写新的view控件
public class ChinaMapView extends View {
private static final String TAG = ChinaMapView.class.getName();
public List<chinaitem> chinaitems = new ArrayList<chinaitem>();
//被点击的区域
private chinaitem selectItem;
//缩放1.3倍
public float scale = 1.3f;
private Context mContext;
private Paint mPaint;
private int[] colors = new int[]{0xFF239BD7,0xFF30A9E5,0xFF80CBF1,0xFFF0E68C};
GestureDetectorCompat gestureDetectorCompat;
public ChinaMapView(Context context) {
super(context);
}
public ChinaMapView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context) {
mContext = context;
mPaint = new Paint();
mPaint.setAntiAlias(true);
gestureDetectorCompat = new GestureDetectorCompat(context,new GestureDetector.SimpleOnGestureListener(){
@Override
public boolean onDown(MotionEvent e) {
Log.d(TAG,"onDown x:"+e.getX()+";y:"+e.getY());
handleTouch(e.getX(),e.getY());
return true;
}
});
thread.start();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.scale(scale,scale);
if(taiwanItems != null){
for(chinaitem:taiwanItems){
if(item != selectItem){
item.draw(canvas,mPaint,false);
}
}
if(selectItem != null){
selectItem.draw(canvas,mPaint,true);
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return gestureDetectorCompat.onTouchEvent(event);
}
public void handleTouch(float x,float y){
chinaitem chinaitem = null;
if(chinaitems != null){
for(chinaitem item :chinaitems){
if(item.isTouch((int)(x/scale),(int)(y/scale))){
chinaitem = item;
break;
}
}
if(chinaitem!= null) {
selectItem = chinaitem;
postInvalidate();
}
}
}
Thread thread = new Thread(){
@Override
public void run() {
InputStream inputStream = mContext.getResources().openRawResource(R.raw.chinahigh);
//采用Dom解析器解析xml
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = null;
try {
builder = factory.newDocumentBuilder();
Document doc = builder.parse(inputStream);
Element rootelement = doc.getDocumentElement();
NodeList items = rootelement.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);
TaiWanItem item = new TaiWanItem(path);
taiwanItems.add(item);
}
handler.sendEmptyMessage(1);
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
};
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
if(taiwanItems == null || taiwanItems.size()==0)
return;
int colorNum = taiwanItems.size();
int color = Color.WHITE;
//赋予颜色
for(int i=0;i<colorNum;i++){
int flag = i % 4;
switch(flag){
case 1:
color = colors[0];
break;
case 2:
color = colors[1];
break;
case 3:
color = colors[1];
break;
default:
color = colors[2];
}
chinaitem.get(i).setDrawColor(color);
}
postInvalidate();
}
};
}
这样我们就实现了地图显示,之后我们要在Activity里使用它,并且在后台Java代码里
再次重载onTouch函数来完成变色和取值。在那之前,我们先定义这样一个字符串
String[] pos=new String[]{"安徽","北京","重庆","福建","广东","甘肃","广西"
,"贵州","海南","河北","河南","香港","黑龙江","湖南","湖北","吉林"
,"江苏","江西","辽宁","澳门","内蒙古","宁夏","青海","陕西","四川","山东","上海","山西","天津","台湾","新疆","西藏","云南","浙江"};
由于地图的构筑是靠一个Arraylist数组逐个完成的,所以可以用这个字符串按照构造时的直接得到点击时的地理位置(我就没呢么好运啦,是照着返回结果和地图一个个对过来的。)
之后重写控件的onTouch函数:
tp.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
for(int i=0;i<tp.chinaitem.size();i++) {
if(tp.chinaitem.get(i).isTouch((int)(event.getX()/tp.scale),(int)(event.getY()/tp.scale))){
op.setText(pos[i]);
tp.handleTouch(event.getX(),event.getY());
po.setText("该省/直辖市/特别行政区有"+dao.sere(pos[i]).size()+"条记录,其中异常记录"+dao.sered(pos[i]).size()+"条");
os.setVisibility(View.VISIBLE);
break;
}else {
os.setVisibility(View.INVISIBLE);
}
}
return true;
}
});
其中先调用了isTouch函数判断触点是否在合法区域,之后再调用handleTouch函数改变颜色。
最后的效果就像这样:

好,这就算成功了!那么今天就到这里,我们明天见咯!

浙公网安备 33010602011771号