Android 绘制中国地图

Android 绘制中国地图,第1张

概述最近的版本有这样一个需求:有3个要素:中国地图高亮省区中心显示数字面对这样一个需求,该如何实现呢?高德地图因为项目是基于高德地图来做的,所以很自然而然的想到了高德。但是当查阅高德地图相关Api后,发现并没有能够实现这样需求的方法,所以只能另寻他法了。图片叠加让设计

最近的版本有这样一个需求:

有 3 个要素:

中国地图高亮省区中心显示数字

面对这样一个需求,该如何实现呢?

高德地图

因为项目是基于高德地图来做的,所以很自然而然的想到了高德。但是当查阅高德地图相关 API 后,发现并没有能够实现这样需求的方法,所以只能另寻他法了。

图片叠加

让设计师出图,实现第一个要素开发成本极低。至于高亮省区,也是继续让设计师出图,与全国地图分辨率保持一致,为每个省区设计一张高亮的图,其他地方透明,这样算下来设计师得出 35 张图。若不考虑性能,将图片无脑叠加倒也可以实现。但是作为 AndroID 开发都知道,这样的一张不算小的图片加载到手机里,占用的内存怕是个庞然大物,更别谈极端情况下要叠加 35 张这样的大图了。
优化下叠加方案:将高亮的省区做成小图,一个包含了省区所有区域的矩形,省区内部高亮,其他区域透明,这样图变小了,但是就得计算小图相对于全国大图的相对位置,对于每个小图都得计算一个比例。同时,绘制高亮省区时可以每次都只取2张图进行叠加,叠加完后释放一张图再加载另一张图,而不用一次性全部加载在内存中。这种方案想想是 ok 的,但是感觉依然还是很麻烦。于是继续探索~

SVG Path

其实网上有很多文章也是有类似的需求,简单搜一下就发现了 SVG 这个解决方案了。看了一眼,便决定就是它了!
SVG:可缩放矢量图形(英语:scalable Vector Graphics,SVG)是一种基于可扩展标记语言(XML),用于描述二维矢量图形的图形格式。元素是 SVG 基本形状中最强大的一个,它不仅能创建其他基本形状,还能创建更多其他形状。

SVG Path 用 AndroID 绘制

这里先贴一下我找的北京市的 Path 数据:

1
2
3
<svg height="475" wIDth="565">
<path ID="Beijing" d="M421.139,189.75L420.782,186.894L419.95,184.989L425.045,182.863L425.426,181.18L424.23699999999997,176.413H422.56899999999996L415.90299999999996,172.964L412.21299999999997,176.654C412.21299999999997,176.654,411.08799999999997,183.239,411.381,181.534C411.66999999999996,179.82999999999998,407.688,185.822,407.688,185.822L407.094,190.108L407.926,192.371L412.807,191.537L416.5,192.608L418.284,190.941L421.139,189.75Z"/>
</svg>

这里要注意一点:SVG Path 里的数据都是在一个固定宽高的矩形里的坐标集合,所以当 AndroID VIEw 与 SVG 的宽高不一致时,需要进行缩放。注意下面代码中的 scale 属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

* 计算地图边界
* 1.黑龙江是中国最东,最北的省份
* 2.新疆是中国最西的省份
* 3.海南是中国最南的省份
*/
private fun () {
val hljRF = RectF()
xPaths[HEILONGJIANG_CODE]?.computeBounds(hljRF, true)

val hnRF = RectF()
xPaths[HAINAN_CODE]?.computeBounds(hnRF, true)

mapWIDth = hljRF.right
mapHeight = hnRF.bottom
}

overrIDe fun onMeasure(wIDthMeasureSpec: Int, heightmeasureSpec: Int) {
super.onMeasure(wIDthMeasureSpec, heightmeasureSpec)
val speSize = VIEw.MeasureSpec.getSize(wIDthMeasureSpec)
scale = speSize / mapWIDth
setMeasuredDimension(speSize, (speSize * mapHeight / mapWIDth).toInt())
}

overrIDe fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
// 缩放画布
canvas.scale(scale, scale)
...
}

再来看到 Path 里有一些 M、L、Z 等字符,这些都是 Path 元素里的指令,后面紧跟的数字即是坐标。

M x,y 移动指令,映射 Path 中的 moveto
L x,y 画直线指令,映射 Path 中的 lineto
H x 画水平线指令,映射 Path 中的 lineto,不过要使用上一个坐标的 y
V y 画垂直线指令,映射 Path 中的 lineto,不过要使用上一个坐标的 x
C x1,y1,x2,y2,x,y 三次贝塞尔曲线指令,映射 Path 中的 cubicTo
S x2,y2,x,y 跟在 C 指令后面使用,用 C 指令的结束点做控制点,映射 cubicTo
Q x1,y1,x,y 二次贝塞尔曲线指令,映射 quadTo
T x,y 跟在 Q 指令后面使用,使用 Q 的 x,y 做控制点,映射 quadTo
Z path 关闭指令,映射 close

注意小写指令为使用相对坐标,下面 2 行 Path 得到的结果是一样的:

1
2
M421.139,189.75L420.782,186.894
M421.139,189.75l-0.357,-2.856

基于 AndroID Path 实现不了小写指令的那种效果,所以只能使用大写指令。这里贴一下一个将 SVG Path 转成 AndroID Path 的工具类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
大专栏
总结

以上是内存溢出为你收集整理的Android 绘制中国地图全部内容,希望文章能够帮你解决Android 绘制中国地图所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1067853.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-26
下一篇 2022-05-26

发表评论

登录后才能评论

评论列表(0条)

保存