25 java android google-maps google-maps-markers
我正在尝试根据折线和动画移动标记.与下图类似:
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);
}
Run Code Online (Sandbox Code Playgroud)
和动画:
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);
}
}
}
});
}
Run Code Online (Sandbox Code Playgroud)
And*_*nko 26
您可以根据自定义标记动画为您的任务使用您的方法:在所有方向点分别为汽车运动和汽车转弯设置动画.为此您需要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();
}
}
});
}
Run Code Online (Sandbox Code Playgroud)
哪里
mMarkerIcon 是:
Bitmap mMarkerIcon;
...
mMarkerIcon = BitmapFactory.decodeResource(getResources(), R.drawable.the_car); // for your car icon in file the_car.png in drawable folder
Run Code Online (Sandbox Code Playgroud)
和汽车图标应该是朝北的:
适用于正确的旋转
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);
}
}
Run Code Online (Sandbox Code Playgroud)
反过来车转动画方法可以是这样的:
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();
}
}
});
}
Run Code Online (Sandbox Code Playgroud)
在哪里nextMoveAnimation():
private void nextMoveAnimation() {
if (mIndexCurrentPoint < mPathPolygonPoints.size() - 1) {
animateCarMove(mCarMarker, mPathPolygonPoints.get(mIndexCurrentPoint), mPathPolygonPoints.get(mIndexCurrentPoint+1), MOVE_ANIMATION_DURATION);
}
}
Run Code Online (Sandbox Code Playgroud)
该mPathPolygonPoints(开车出行的geopoints)是:
private List<LatLng> mPathPolygonPoints;
Run Code Online (Sandbox Code Playgroud)
并且mIndexCurrentPoint变量是路径上当前点的索引(在动画开始时它应该是0并且在nextTurnAnimation()方法的每个路径上增加).
TURN_ANIMATION_DURATION - 汽车开启路径geopoint的持续时间(毫秒)动画;
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));;
}
Run Code Online (Sandbox Code Playgroud)
最后,您可以通过调用animateCarMove()一次启动所有动画:
animateCarMove(mCarMarker, mPathPolygonPoints.get(0), mPathPolygonPoints.get(1), MOVE_ANIMATION_DURATION);
Run Code Online (Sandbox Code Playgroud)
对于汽车路径的每个点,将自动调用其他动画步骤.
你应该考虑一些"特殊情况",如:
1)改变转角的符号(例如轴承从-120度变化到150度);
2)用户中断动画的可能性;
3)计算路径段长度上的动画持续时间(例如,1 km的段长度而不是固定的1秒MOVE_ANIMATION_DURATION)
4)可能调整价值16以handler.postDelayed(this, 16);获得更好的表现;
5)等等.
我认为您正在寻找的是Marker Animations。
您可以为标记设置动画,以便它们在各种不同的情况下表现出动态运动。要指定标记的动画方式,请使用标记的动画属性(类型为 google.maps.Animation)。支持以下动画值:
-DROP 表示标记首次放置在地图上时应从地图顶部掉落到其最终位置。一旦标记停止,动画就会停止,动画将恢复为空。这种类型的动画通常在创建标记期间指定。
-BOUNCE 表示标记应弹回原位。弹跳标记将继续弹跳,直到其动画属性显式设置为 null。
以下是该指南的摘录:
var marker;
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 13,
center: {lat: 59.325, lng: 18.070}
});
marker = new google.maps.Marker({
map: map,
draggable: true,
animation: google.maps.Animation.DROP,
position: {lat: 59.327, lng: 18.067}
});
marker.addListener('click', toggleBounce);
}
function toggleBounce() {
if (marker.getAnimation() !== null) {
marker.setAnimation(null);
} else {
marker.setAnimation(google.maps.Animation.BOUNCE);
}
}
Run Code Online (Sandbox Code Playgroud)