地图的轮廓看起来是不规则的,不规则轮廓就是地图的路线。路线在手,说走就走。我们一起来写一个矢量地图。

先来了解矢量图形,XML 文件中定义为一组点、一组线条和一组曲线及其相关颜色信息。

矢量图形 svg 用 XML语言来编写,文件是纯粹的 XML

SVG 图像在放大或改变尺寸的情况下其图形质量不会有所损失

SVG 是W3C的标准

可在图像质量不下降的情况下被放大

使用矢量图形的主要优势在于图片可缩放。可以在不降低显示质量的情况下缩放图片。也就是说,可以针对不同的屏幕密度调整同一文件的大小,而不会降低图片质量。不仅能缩减 APK 文件大小,还能减少开发者维护工作。您还可以对动画使用矢量图片,使用多个 XML 文件,而不是多张图片。

Android 5.0(API 级别 21)是第一个使用矢量图像的。使用兼容看可以支持更低的版本。

绘制地图的轮廓

我们是怎么绘制地图轮廓的呢?

新建了一个属性文件 attrs.xml

我们在布局main布局文件中 activity_main.xml

xmlns:app="http://schemas.android.com/apk/res-auto"

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent"

tools:context=".MainActivity">

android:layout_width="match_parent"

android:layout_height="wrap_content"

app:isOnlyProfile="true" />

在MapView.java文件中,获取是否仅仅显示轮廓的属性值

/**

* 是否仅仅绘制轮廓

*/

private boolean isOnlyProfile;

public MapView(Context context, @Nullable AttributeSet attrs) {

this(context, attrs, 0);

}

public MapView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

init(context, attrs);

}

private void init(Context context, AttributeSet attrs) {

TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MapView);

isOnlyProfile = typedArray.getBoolean(R.styleable.MapView_isOnlyProfile, false);

typedArray.recycle();

this.mContext = context;

mPaint = new Paint();

mPaint.setAntiAlias(true);

loadPathData();

}

我们接下来获取控件的宽度,我们以屏幕宽度为主

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

// map 的宽度 和高度

if (mMapRect != null) {

double mapWidth = mMapRect.width();

//控件宽度

int width = MeasureSpec.getSize(widthMeasureSpec);

int height = MeasureSpec.getSize(heightMeasureSpec);

int finalWidth = Math.min(width, height);

//计算控件宽度和地图宽度的比例 比如

//以屏幕宽度为主

mScale = (float) (finalWidth / mapWidth);

Log.d("tag", "-------scale=" + mScale);

}

}

这部分代码很简单

我们的地图路线是怎么生成的呢?

地图路线是美工或者UI设计师已经画好了的,是一个china.svg 文件,用一个xml文件描述,比如我们画一个圆圈,用svg怎么做呢?

svg 菜鸟教程

有很多的学习教程

加载地图路线数据

/**

* 解析svg 矢量图数据

*/

private void loadPathData() {

//获取矢量图输入流

InputStream inputStream = mContext.getResources().openRawResource(R.raw.china);

List list = new ArrayList<>();

try {

//文档施工队工厂

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

//文档施工队的某位师傅

DocumentBuilder builder = factory.newDocumentBuilder();

//w3c 的Document

Document document = builder.parse(inputStream);

//文档中的根元素

Element rootElement = document.getDocumentElement();

//获取名称为path 的节点列表

NodeList items = rootElement.getElementsByTagName("path");

// 中国地图的 矩形

float left = -1;

float right = -1;

float top = -1;

float bottom = -1;

RectF rect = new RectF();

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

//要绘制的地图颜色,随机生成要绘制的地图颜色

int color;

int flag = i % 4;

switch (flag) {

case 1:

color = ContextCompat.getColor(mContext, R.color.deep_sky_blue);

break;

case 2:

color = ContextCompat.getColor(mContext, R.color.cerulean_blue);

break;

case 3:

color = ContextCompat.getColor(mContext, R.color.light_sky_blue);

break;

default:

color = ContextCompat.getColor(mContext, R.color.cyan);

break;

}

// 一条省份路线数据

ProvinceItem provinceItem = new ProvinceItem(path, color, mContext);

list.add(provinceItem);

//获取宽高

path.computeBounds(rect, true);

//获取地图大小,也就是地图的边界

left = left == -1 ? rect.left : Math.min(left, rect.left);

right = right == -1 ? rect.right : Math.max(right, rect.right);

top = top == -1 ? rect.top : Math.min(top, rect.top);

bottom = bottom == -1 ? rect.bottom : Math.max(bottom, rect.bottom);

mMapRect.set(left, top, right, bottom);

}

mProvinceItemList = list;

} catch (Exception e) {

e.printStackTrace();

}

}

获取矢量图输入流,创建了一个文档施工队工厂,创建一个文档施工队师傅解析矢量图输入流,接着获取文档根元素,获取根元素中的path节点列表,通过android:pathData获取每个节点值。这个值就是一个省的路线。我们通过PathParser类解析为一个android的Path对象 Path path = PathParser.createPathFromPathData(pathData); 有了路线,说走就走,接下来我们看看怎么绘制地图轮廓。 PathParse类在android.util下,我们通过Everything搜索某个类。

@Override

protected void onDraw(Canvas canvas) {

if (mProvinceItemList != null) {

canvas.save();

canvas.scale(mScale, mScale);

for (ProvinceItem provinceItem : mProvinceItemList) {

if (provinceItem != this.mSelectProvinceItem) {

provinceItem.drawItem(canvas, mPaint, false,isOnlyProfile);

} else {

provinceItem.drawItem(canvas, mPaint, true,isOnlyProfile);

}

}

}

}

/**

* 绘制某一个省的地图路线

*

* @param canvas

* @param paint

* @param isSelect 是否选中

* @param isOnlyProfile 是否仅仅绘制轮廓

*/

void drawItem(Canvas canvas, Paint paint, boolean isSelect, boolean isOnlyProfile) {

if (isSelect) {

//清除阴影层

paint.clearShadowLayer();

//设置边界

paint.setStyle(Paint.Style.STROKE);

paint.setStrokeWidth(2);

paint.setColor(Color.MAGENTA);

paint.setShadowLayer(6, 0, 0, Color.BLUE);

// radius:模糊半径,radius越大越模糊,越小越清晰,但是如果radius设置为0,则阴影消失不见

// dx:阴影的横向偏移距离,正值向右偏移,负值向左偏移

// dy:阴影的纵向偏移距离,正值向下偏移,负值向上偏移

// color: 绘制阴影的画笔颜色,即阴影的颜色(对图片阴影无效)

canvas.drawPath(mPath, paint);

if (isOnlyProfile) {

return;

}

//选中时,绘制描边效果

paint.setStyle(Paint.Style.FILL);

paint.setColor(mDrawColor);

paint.setStrokeWidth(1);

canvas.drawPath(mPath, paint);

} else {

//设置边界

paint.setStyle(Paint.Style.STROKE);

paint.setStrokeWidth(1);

paint.setColor(Color.BLACK);

paint.setShadowLayer(8, 0, 0, Color.WHITE);

canvas.drawPath(mPath, paint);

if (isOnlyProfile) {

return;

}

//后面是填充

paint.clearShadowLayer();

paint.setColor(mDrawColor);

paint.setStyle(Paint.Style.FILL);

paint.setStrokeWidth(2);

canvas.drawPath(mPath, paint);

}

}

onDraw方法中通过遍历每一个省份,绘制每一个省的路线图。isOnlyProfile 如果为真仅仅绘制轮廓,绘制轮廓主要就是canvas.drawPath()方法,第一个参数传递的是要绘制路线,第二个是画笔。就这样我们就绘制了地图轮廓图。如果仅仅绘制轮廓为假,绘制五彩斑斓的地图。

我们点击地图,会有选中效果,这部分是怎么做的呢?

判断点击哪个省份

@Override

public boolean onTouchEvent(MotionEvent event) {

handleTouch(event.getX(), event.getY());

return super.onTouchEvent(event);

}

/**

* 点击某个省份进行绘制

*

* @param x 点击x坐标

* @param y 点击y坐标

*/

private void handleTouch(float x, float y) {

if (mProvinceItemList == null) {

return;

}

for (ProvinceItem provinceItem : mProvinceItemList) {

if (provinceItem.isTouch(x / mScale, y / mScale)) {

mSelectProvinceItem = provinceItem;

postInvalidate();

break;

}

}

}

/**

* true 包含点击的x y 左边

*

* @param x 坐标

* @param y 坐标

* @return

*/

public boolean isTouch(float x, float y) {

RectF rectF = new RectF();

/**

* 获取路径的举行

*/

mPath.computeBounds(rectF, true);

// rectF 矩形 包含了Path

Region region = new Region();

//设置路径范围

region.setPath(mPath, new Region((int) rectF.left, (int) rectF.top, (int) rectF.right, (int) rectF.bottom));

//x y 是否在这个坐标中

return region.contains((int) x, (int) y);

}

在onTouchEvent方法中获取手指点击屏幕的x,y坐标,判断是在哪个省份中。 region.setPath是取路线和矩形的较劲,最后判断是否在这个区域中。

下一节我们来聊聊svg矢量动画。

android矢量地图画法_Android 我们的矢量地图,放大不失真相关推荐

  1. android 中间凹背景_Android开发仿百度地图的凹陷BottomNavigationView

    释放双眼,带上耳机,听听看~! 百度的: 71529789c6c948803e1075c2c7e00809.jpg 我的: e9347423eb2031228af77ad63d7b01d7.jpg 使 ...

  2. 科研论文绘图:ppt, word,latex,python matplotlib绘图 ,矢量图,高清图,放大不失真

    目录 1. 用PPT绘图,保存为高清图片,不推荐使用,方法链接 2. 用PPT绘图,保存为emf矢量图,适合插入word,方法链接 3. 用PPT画图,保存为eps文件,适合插入latex,方法链接 ...

  3. android 矢量图形文件,Android Studio进行APP设计开发之矢量图及XML文件转换

    Android Studio进行APP设计开发之矢量图及XML文件转换 当我们使用Android studio进行APP设计开发时,会用到矢量图,那么要将矢量图运用到安卓工程drawable中去,就需 ...

  4. 提取某一个镇的行政边界_高德地图api获取行政边界矢量方法

    高德地图api获取行政边界矢量方法 发布时间:2018-09-07 17:51, 浏览次数:2170 , 标签: api 1.获取高德地图web服务key 2.行政区域查询API服务地址: https ...

  5. Android Studio进行APP设计开发之矢量图及XML文件转换

    Android Studio进行APP设计开发之矢量图及XML文件转换 当我们使用Android studio进行APP设计开发时,会用到矢量图,那么要将矢量图运用到安卓工程drawable中去,就需 ...

  6. google map谷歌地图瓦片地址无偏移矢量地图电子地图影像地图

    前几天做谷歌地图踩大坑,目前网上很多文字的瓦片地址是可以访问但,矢量地图有偏移,你将矢量地图和影像地图同时加载出来就会发现两个地图不能完全的重合,而且连标注都没有和地图重合.那是因为矢量地图做了偏移影 ...

  7. Android中级篇之百度地图SDK v3.5.0-基础地图[图解百度地图基础教程]

    基础地图[比官方更详细] 简介 开发者可利用SDK提供的接口,使用百度为您提供的基础地图数据.目前百度地图SDK所提供的地图等级为3-19级,所包含的信息有建筑物.道路.河流.学校.公园等内容.所有叠 ...

  8. delphi bmp绘制矢量文件效率慢_聊一聊矢量瓦片的常识

    一.矢量瓦片的基本原理和相关格式 现阶段,电子地图瓦片主要使用两种方式,一种是传统的栅格瓦片,另外一种是新出的矢量瓦片(Vector Tiles),前者是采用四叉树金字塔模型的分级方式,将地图切割成无 ...

  9. mapgis矢量化怎么打分数_MAPGIS矢量化操作步骤

    MAPGIS 矢量化操作步骤 MAPGIS 矢量化步骤 1. 利用 MAPGIS 矢量化作图. 1.1 启动 MAPGIS( 方法过程见上一次实验 ) . 1.2 进行输入编辑窗口. (1) 点击&q ...

  10. [android] 百度地图开发 (一).申请AK显示地图及解决显示空白网格问题

        最近做android百度地图,但是使用baidumapapi_v2_3_1.jar和libBaiduMapSDK_v2_3_1.so显示百度地图时总是遇到问题--只显示网格而没有显示地图,网络 ...

最新文章

  1. 基于数组实现循环队列(基于Java实现)
  2. Andrej Karpathy发文谈神经网络:这不仅仅是分类器,这是一种新的软件开发思想
  3. ActiveMQ消息中间件简明笔记(1)——理论知识点整理
  4. 从计算机移到u盘如何加快速度,我的电脑移动文件到U盘里时进度很慢很慢,怎么让它变快?...
  5. CImage类的使用介绍!
  6. 用Navicat管理MySQL数据库
  7. 1949:【10NOIP普及组】数字统计
  8. 页面每次添加都显示最后一次访问记录spring scope=prototype 学习笔记
  9. 软齿面主要失效形式_齿轮4种常见故障原因,如何采取预防措施,避免齿轮失效...
  10. Oracle DBA手记3:数据库性能优化与内部原理解析
  11. 帮您管好云:阿里云混合云管理平台发布 | 凌云时刻
  12. java 全双工串口,Java实现全双工串口通信
  13. 科研必备 | 谷歌学术高级搜索详解
  14. 【EXLIBRIS】#小词旮旯# 001 Lock
  15. MMKV 组件-快速丶读丶查丶写的sp
  16. 2018年要过去了,年初说好要上完的网课呢?
  17. Could not chdir to home directory /home/xxx:Permission denied
  18. 通过javaMail发送邮件,可选添加多个收件人,密送,抄送,多个附件,超实用
  19. Android4.2.2下Stagefright多媒体架构中的A31的OMX插件和Codec组件
  20. 在一个html页面加载另一个html页面

热门文章

  1. 教程篇(6.4) 02. 路由、会话和性能SLA ❀ SD-WAN ❀ Fortinet 网络安全架构师 NSE7
  2. 安卓智能手机完全装机手册,让安卓拥有无限可能!
  3. Kali linux 学习笔记(十三)主动信息收集——端口扫描(UDP扫描、TCP扫描) 2020.2.22
  4. 百度飞桨PaddlePaddle 顶会论文复现课程 阅读心得 BigGAN
  5. 【论文译文】BigGAN
  6. 机器视觉——光源选型
  7. 运筹学教学|十分钟快速掌握割平面法及对偶单纯形法(附Java代码及算例)
  8. 使用_beginthread创建线程
  9. Linux下安装Java运行环境
  10. 通俗易懂解释信源编码与信道编码的区别与联系