我正在尝试根据折线和动画移动标记。类似于下图:
Mapbox已经提供了这种演示。但我想使用谷歌地图实现同样的目标。但是现在我的标记没有沿着路径旋转。这是我尝试过的:
private void onReady(List<LatLng> polyz) {
for (int i = 0; i < polyz.size() - 1; i++) {
LatLng src = polyz.get(i);
LatLng dest = polyz.get(i + 1);
Polyline line = map.addPolyline(new PolylineOptions()
.add(new LatLng(src.latitude, src.longitude),
new LatLng(dest.latitude, dest.longitude))
.width(2).color(Color.RED).geodesic(true));
}
LatLngBounds.Builder builder = new LatLngBounds.Builder();
builder.include(polyz.get(0));
builder.include(polyz.get(polyz.size()-1));
map.moveCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), 48));
map.animateCamera(CameraUpdateFactory.zoomTo(7), 1000, null);
BitmapDescriptor icon = BitmapDescriptorFactory.fromResource(R.drawable.car);
marker = map.addMarker(new MarkerOptions()
.position(polyz.get(0))
.title("Curr")
.snippet("Move"));
marker.setIcon(icon);
}
和动画:
private void animateMarker(GoogleMap myMap, final Marker marker, final List<LatLng> directionPoint,
final boolean hideMarker) {
final Handler handler = new Handler();
final long start = SystemClock.uptimeMillis();
Projection proj = myMap.getProjection();
final long duration = 600000;
final Interpolator interpolator = new LinearInterpolator();
handler.post(new Runnable() {
int i = 0;
@Override
public void run() {
long elapsed = SystemClock.uptimeMillis() - start;
float t = interpolator.getInterpolation((float) elapsed
/ duration);
Location location=new Location(String.valueOf(directionPoint.get(i)));
Location newlocation=new Location(String.valueOf(directionPoint.get(i+1)));
marker.setAnchor(0.5f, 0.5f);
marker.setRotation(location.bearingTo(newlocation) - 45);
if (i < directionPoint.size()) {
marker.setPosition(directionPoint.get(i));
}
i++;
if (t < 1.0) {
// Post again 16ms later.
handler.postDelayed(this, 16);
} else {
if (hideMarker) {
marker.setVisible(false);
} else {
marker.setVisible(true);
}
}
}
});
}
您可以将基于自定义标记动画的方法用于您的任务:在所有方向点上分别为汽车运动和汽车转弯设置动画。为此,您需要 2 种动画:
1) 汽车运动动画;
2)汽车转弯动画;
它在其末端相互调用(末端的汽车运动动画调用汽车转弯动画,反之亦然:汽车末端的汽车转弯动画调用汽车运动动画等对于汽车路径的所有点)。
例如上图:
1) 汽车从
P0
到 的运动动画P1
;2) 汽车启动动画
P1
;3)汽车从
P1
到的运动动画P2
等等。
汽车运动动画可以通过这样的方法实现:
private void animateCarMove(final Marker marker, final LatLng beginLatLng, final LatLng endLatLng, final long duration) { final Handler handler = new Handler(); final long startTime = SystemClock.uptimeMillis(); final Interpolator interpolator = new LinearInterpolator(); // set car bearing for current part of path float angleDeg = (float)(180 * getAngle(beginLatLng, endLatLng) / Math.PI); Matrix matrix = new Matrix(); matrix.postRotate(angleDeg); marker.setIcon(BitmapDescriptorFactory.fromBitmap(Bitmap.createBitmap(mMarkerIcon, 0, 0, mMarkerIcon.getWidth(), mMarkerIcon.getHeight(), matrix, true))); handler.post(new Runnable() { @Override public void run() { // calculate phase of animation long elapsed = SystemClock.uptimeMillis() - startTime; float t = interpolator.getInterpolation((float) elapsed / duration); // calculate new position for marker double lat = (endLatLng.latitude - beginLatLng.latitude) * t + beginLatLng.latitude; double lngDelta = endLatLng.longitude - beginLatLng.longitude; if (Math.abs(lngDelta) > 180) { lngDelta -= Math.signum(lngDelta) * 360; } double lng = lngDelta * t + beginLatLng.longitude; marker.setPosition(new LatLng(lat, lng)); // if not end of line segment of path if (t < 1.0) { // call next marker position handler.postDelayed(this, 16); } else { // call turn animation nextTurnAnimation(); } } }); }
在哪里
mMarkerIcon
是:Bitmap mMarkerIcon; ... mMarkerIcon = BitmapFactory.decodeResource(getResources(), R.drawable.the_car); // for your car icon in file the_car.png in drawable folder
和汽车图标应该朝北:
正确旋转应用
nextTurnAnimation()
- 在汽车运动动画结束时调用方法以启动汽车转弯动画:private void nextTurnAnimation() { mIndexCurrentPoint++; if (mIndexCurrentPoint < mPathPolygonPoints.size() - 1) { LatLng prevLatLng = mPathPolygonPoints.get(mIndexCurrentPoint - 1); LatLng currLatLng = mPathPolygonPoints.get(mIndexCurrentPoint); LatLng nextLatLng = mPathPolygonPoints.get(mIndexCurrentPoint + 1); float beginAngle = (float)(180 * getAngle(prevLatLng, currLatLng) / Math.PI); float endAngle = (float)(180 * getAngle(currLatLng, nextLatLng) / Math.PI); animateCarTurn(mCarMarker, beginAngle, endAngle, TURN_ANIMATION_DURATION); } }
轮到汽车转弯动画方法可以是这样的:
private void animateCarTurn(final Marker marker, final float startAngle, final float endAngle, final long duration) { final Handler handler = new Handler(); final long startTime = SystemClock.uptimeMillis(); final Interpolator interpolator = new LinearInterpolator(); final float dAndgle = endAngle - startAngle; Matrix matrix = new Matrix(); matrix.postRotate(startAngle); Bitmap rotatedBitmap = Bitmap.createBitmap(mMarkerIcon, 0, 0, mMarkerIcon.getWidth(), mMarkerIcon.getHeight(), matrix, true); marker.setIcon(BitmapDescriptorFactory.fromBitmap(rotatedBitmap)); handler.post(new Runnable() { @Override public void run() { long elapsed = SystemClock.uptimeMillis() - startTime; float t = interpolator.getInterpolation((float) elapsed / duration); Matrix m = new Matrix(); m.postRotate(startAngle + dAndgle * t); marker.setIcon(BitmapDescriptorFactory.fromBitmap(Bitmap.createBitmap(mMarkerIcon, 0, 0, mMarkerIcon.getWidth(), mMarkerIcon.getHeight(), m, true))); if (t < 1.0) { handler.postDelayed(this, 16); } else { nextMoveAnimation(); } } }); }
在哪里
nextMoveAnimation()
:private void nextMoveAnimation() { if (mIndexCurrentPoint < mPathPolygonPoints.size() - 1) { animateCarMove(mCarMarker, mPathPolygonPoints.get(mIndexCurrentPoint), mPathPolygonPoints.get(mIndexCurrentPoint+1), MOVE_ANIMATION_DURATION); } }
该
mPathPolygonPoints
(开车出行的geopoints)是:private List<LatLng> mPathPolygonPoints;
和
mIndexCurrentPoint
变量是在路径当前点的索引(它应该是0,在动画的开始和递增在路径的每匝nextTurnAnimation()
方法)。TURN_ANIMATION_DURATION
- 汽车开启路径地理点的持续时间(以毫秒为单位)动画;MOVE_ANIMATION_DURATION
- 汽车沿路径线段移动的持续时间(以毫秒为单位)动画;要获得轴承您可以使用这样的方法:
private double getAngle(LatLng beginLatLng, LatLng endLatLng) { double f1 = Math.PI * beginLatLng.latitude / 180; double f2 = Math.PI * endLatLng.latitude / 180; double dl = Math.PI * (endLatLng.longitude - beginLatLng.longitude) / 180; return Math.atan2(Math.sin(dl) * Math.cos(f2) , Math.cos(f1) * Math.sin(f2) - Math.sin(f1) * Math.cos(f2) * Math.cos(dl));; }
最后,您可以通过调用
animateCarMove()
一次来启动所有动画:animateCarMove(mCarMarker, mPathPolygonPoints.get(0), mPathPolygonPoints.get(1), MOVE_ANIMATION_DURATION);
将为汽车路径的每个点自动调用其他动画步骤。
您应该考虑一些“特殊情况”,例如:
1) 改变转向角的符号(例如方位角从-120度变为150度);
2) 用户中断动画的可能性;
3) 计算路径段长度的动画持续时间(例如,1 公里段长度为 1 秒而不是固定
MOVE_ANIMATION_DURATION
)4) 可能调整值
16
以handler.postDelayed(this, 16);
获得更好的性能;5)等等。