之前就想做个仿滴滴首页车辆平滑移动的效果,但是一直没有时间。最近翻看旧项目的时候又看到这个需求,想了想还是花点时间做一下吧。先上效果图。 源码在文章结尾
先是滴滴的效果图
再然后是demo的效果图
首先当然是用大百度搜搜看,有没有类似的效果,结果首先发现了这个博主的文章,粗略看了一下,只是简单的实现了一次车辆的平滑移动,达不到要求。于是就在他的Demo上继续修改。看网上有些人说车辆的位置信息是滴滴从服务端返回回来的真实坐标,我看了一下滴滴的效果,感觉应该不是,因为有的车辆都已经横穿建筑物,连跨海的都有,应该是随机生成的坐标。
1、确定平滑移动的范围
随机生成的车辆坐标需要在指定的范围内,肯定不能说让车辆在地图上到处跑。那怎么判断生成的坐标在指定范围内呢?这时候我们可以考虑用指定坐标为圆心,指定半径范围内画圆,把这个圆范围内的坐标当成可用坐标,然后调用高德的方法mCircle.contans()来判断生成的坐标是否在指定范围内来区分。
/**
* 生成以中心点附近指定radius内的坐标数组
*
* @param startLatLng 起点坐标
* @return
*/
private ArrayList<LatLng> randomGenerateLatLngs(LatLng startLatLng) {
ArrayList<LatLng> latLngs = new ArrayList<>();
latLngs.add(startLatLng);
double lat = centerLatLng.latitude;
double lng = centerLatLng.longitude;
for (int i = 0; i < 50; i++) {
double newLat = lat + (10 - (Math.random() * 20)) / Math.pow(10, new Random().nextInt(3) + 1);
double newLng = lng + (10 - (Math.random() * 20)) / Math.pow(10, new Random().nextInt(3) + 1);
LatLng newLatLng = new LatLng(newLat, newLng);
if (mCircle.contains(newLatLng)) {
latLngs.add(newLatLng);
}
}
// 如果随机生成的数组个数为0,则再随机添加一个距离中心点更近的坐标
if (latLngs.size() == 1) {
latLngs.add(new LatLng(lat + (Math.random() > 0.5 ? 1 : -1) / Math.pow(10, 3), lng + (Math.random() > 0.5 ? 1 : -1) / Math.pow(10, 3)));
}
return latLngs;
}
PS:请忽略生成随机坐标的完美性,本文主要以实现功能效果为主。
当生成的坐标已经平移完后,我们需要继续生成坐标
smoothMarker.setMoveListener(new MySmoothMoveMarker.MoveListener() {
@Override
public void move(double v) {
}
@Override
public void stop(LatLng latLng) {
ArrayList<LatLng> result = randomGenerateLatLngs(latLng);
startMoveCar(result, index, false);
}
});
这里的MySmoothMoveMarker是我自定义的SmoothMoveMarker,大部分代码都是沿用高德的SmoothMoveMarker,主要是为了增加每次平移动画轨迹结束的回调和旋转动画。具体看源码就知道。
2、添加旋转动画
每当车辆移动到下一个点后,还需要先旋转角度,再执行平移动画,不过平移动画原先就有了,这里我们只需要在平移动画之前添加一个旋转动画,在旋转动画后再执行平移动画就好了,当然时间可以按自己喜好来分配。首先我们需要知道上一次车辆平移的角度
// 上一次车辆平移角度
float lastRotate = getRotate(tempPosition,var5);
和当前车辆平移的角度
// 当前车辆平移角度
float var7 = MySmoothMoveMarker.this.getRotate(var5, var9);
然后就是按顺序执行动画
MySmoothMoveMarker.this.marker.setRotateAngle(360.0F - var7 + MySmoothMoveMarker.this.mAMap.getCameraPosition().bearing);
RotateAnimation rotateAnimation = new RotateAnimation(360.0F - lastRotate + MySmoothMoveMarker.this.mAMap.getCameraPosition().bearing,360.0F - var7 + MySmoothMoveMarker.this.mAMap.getCameraPosition().bearing);
rotateAnimation.setInterpolator(new LinearInterpolator());
rotateAnimation.setDuration(var3 / 5);
if (MySmoothMoveMarker.this.exitFlag || Thread.interrupted()) {
MySmoothMoveMarker.this.marker.setAnimation((Animation) null);
return;
}
MySmoothMoveMarker.this.marker.setAnimation(rotateAnimation);
MySmoothMoveMarker.this.marker.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart() {
}
@Override
public void onAnimationEnd() {
MySmoothMoveMarker.this.animation = new TranslateAnimation(var9);
MySmoothMoveMarker.this.animation.setInterpolator(new LinearInterpolator());
MySmoothMoveMarker.this.animation.setDuration(4 *var3 /5);
if (MySmoothMoveMarker.this.exitFlag || Thread.interrupted()) {
MySmoothMoveMarker.this.marker.setAnimation((Animation) null);
return;
}
MySmoothMoveMarker.this.marker.setAnimation(MySmoothMoveMarker.this.animation);
MySmoothMoveMarker.this.marker.startAnimation();
}
});
MySmoothMoveMarker.this.marker.startAnimation();
好吧,我偷懒了,变量名都是沿用SmoothMoveMarker混淆后的名称。
这里需要注意的就是两个动画(旋转和平移动画)的时间之和要跟执行每段平移动画的时间相等。
有需要或者感兴趣的小伙伴可以继续完善。Over!
========下载积分已改为固定1分==================