高德地图轨迹回放 Demo
示例的高德 API Key 已经去掉了,如果运行不起来请自行申请高德 API Key,填入如下区域:
<meta-data
android:name="com.amap.api.v2.apikey"
android:value="<你的Key>"/>
移动端 Android 高德地图轨迹回放 super-uncle-pig · 2019年10月07日 · 120 次阅读 https://wafer.li/https://wafer.li/https://wafer.li/
最近公司要求实现一个轨迹回放功能,想着 JS 都有 demo 的功能,Android 实现起来不还是小菜一碟?
结果显然是我太拿衣服了
- 太长不看 全篇都采用高德 API 实现,基于 3dmap 6.9.2 包
使用 MovingPointOverlay 实现点的平滑移动
使用 AMap.setCustomRenderer 获取每帧回调,绘制走过的线路
- 需求分析 轨迹回放的功能在高德的 JS Demo 上有,具体来说就是点按照既定路线去移动,同时绘制其走过的路线。
那么我们可以将功能拆解为移动点和绘制线路
本来我想着这种常见的功能在网上随便搜搜就能找到的,然而显然是我太 Naive 了。
搜到的唯二相关的内容,其中一个排版很差,而且估计是公司内部代码,没有给出 demo,第二个则是硬怼一个自定义 View,但是地图肯定是要移动放大之类的,自定义 View 也需要做手势控制,实现难度相对较大。
所以最好还是在高德内部框架上实现这个需求。
- API 调研 经过一番查找之后,我找到了 SmoothMoveMarker 可以实现点的平滑移动功能,然而:
SmoothMoveMarker Deprecated
这里不得不吐槽一下高德的混淆策略,它不仅混淆了代码,同时还把文档混淆了,明明各部分文档都是公开的,将其保留在源代码里面也不会增大多少空间,然而这样全部删掉,导致我不得不切一个网页去看它的 API doc,开发效率急剧下降
在查看了高德地图的 API doc 之后,发现这个类是被 MovingPointOverlay 替代了,也就是说我们需要采用 MovingPointOverlay 实现点的平滑移动
- 获取点位置回调 在 MovingPointOverlay 的 API doc 中,有一个方法叫 setMovingListener,当时的我想当然的认为这个就是点移动时的回调设置方法,因此把画线的逻辑放到了里面去。
原先我将动画的总时间设置为 10 秒,此时点跑得比较快,乍一看没什么问题; 但是当我将动画的时间拉长,点跑得很慢的时候,问题就出现了—— setMovingListener 并不是每帧回调!
也就是说,只有当 Marker 跑到下一个路径点的时候,才能绘制上经过的路线!
这显然会导致线路绘制不平滑,达不到需求的要求。
那怎么办呢?这时候我就进入了一段瞎糊弄的时间,尝试着通过自行实现动画效果来完成需求,然而无论是经纬度计算、屏幕像素计算都存在误差,不太可能在短时间能将需求实现。
正当我想着『万策尽きた!』,无聊浏览高德地图 API doc 的时候,突然发现 AMap 有个 runOnDrawFrame() 方法,是用来触发高德地图的重绘的;
既然有这个方法,那就一定有绘制的回调方法!功夫不负有心人,在往下看了几行之后,我终于发现了这个重要的方法 setCustomRenderer(),而且两者意外的离的很近:
runOnDrawFrame And setCustomRenderer
这个方法接受一个 CustomRenderer 参数,那么什么是 CustomRenderer 呢?
CustomRenderer
从这里看,它有一个 onDrawFrame(),正是绘制每一帧的回调接口,那么我们只要将画线逻辑放到里面去就可以了。
当然,我们也不能抛弃 setMovingListener,因为我们需要它来判断是否已经到达终点。
- 实现逻辑 使用 MovingPointOverlay 实现点的平滑移动 使用 AMap.setCustomRenderer 获取每帧回调,绘制经过的线路 使用 MovingPointOverlay.setMovingListener 判断是否已经到达终点,如果到达终点,则清除经过线路的点
- 坑点 无论是 setCustomRenderer 还是 setMovingListener,它们的回调都是在 OPEN GL 线程回调,而不是在主线程回调
因此,如果需要在动画完毕之后更改 UI,就必须使用 runOnUiThread,否则无论你怎么在里面更改 UI,都不会有任何效果