问题
I am using Google Maps API V2 to get the location of the current user and am recording his route by using the onLocationChanged listener. While the user records their route I save all the LatLngs detected at each location change in an arraylist. When the user stops recording their route I place a marker at the first point in the arraylist. My problem now is that I wish to animate the marker through all the points in the arraylist. Can someone please tell me how can I do this?
Things to note is that the array doesn't need sorting because I record the points as they come. I have tried using a for loop to cycle through the array and send the values over but I get an error from the
final LatLng startLatLng = proj.fromScreenLocation(startPoint);
saying "Unknown Source" along with a NullPointer exception.
Here is my code:
case R.id.action_replay:
int o;
for(o=0; o<oldlocPoints.size(); ++o){
if(--o > 1){lastPos = oldlocPoints.get(--o);}
toPos = oldlocPoints.get(++o);
animateMarker(markerStart, lastPos, toPos);
}
return true;
And this is How I try to animate through the markers. The main difficulty I am encountering is that in run() it only seems to want Final type values so I have no idea how to please it.
//Animates marker through the locations saved from the recorded route
public void animateMarker(final Marker marker, LatLng lastPos, final LatLng toPos) {
final long duration = 1600;
final Handler handler = new Handler();
this.lastPos = lastPos;
this.toPos = toPos;
final long start = SystemClock.uptimeMillis();
final int o;
Projection proj = map.getProjection();
Point startPoint = proj.toScreenLocation(lastPos);
final LatLng startLatLng = proj.fromScreenLocation(startPoint);
Log.d(TAG, "" + lastPos + "" + toPos);
final Interpolator interpolator = new AccelerateDecelerateInterpolator();
handler.post(new Runnable() {
@Override
public void run() {
long elapsed = SystemClock.uptimeMillis() - start;
float t = interpolator.getInterpolation((float) elapsed / duration);
double lng = t * toPos.longitude + (1 - t) * startLatLng.longitude;
double lat = t * toPos.latitude + (1 - t) * startLatLng.latitude;
markerStart.setPosition(new LatLng(lat, lng));
//markerStart.setPosition(interpolator.interpolate(t, target, replayEnd));
if (t < 1.0) {
//Post again 16ms later == 60 frames per second
handler.postDelayed(this, 32);
} else {
//Animation ended
}
}
});
}
Can someone please help me?
UPDATE My closest attempt to date is this:
while (i<oldlocPoints.size()){
final long duration = 32;
final Handler handler = new Handler();
final long start = SystemClock.uptimeMillis();
Projection proj = map.getProjection();
final LatLng toPos = oldlocPoints.get(i/3);
Point startPoint = proj.toScreenLocation(oldlocPoints.get(i));
final LatLng startLatLng = proj.fromScreenLocation(startPoint);
final Interpolator interpolator = new AccelerateDecelerateInterpolator();
handler.post(new Runnable() {
@Override
public void run() {
long elapsed = SystemClock.uptimeMillis() - start;
float t = interpolator.getInterpolation((float) elapsed / duration);
double lng = t * toPos.longitude + (1 - t) * startLatLng.longitude;
double lat = t * toPos.latitude + (1 - t) * startLatLng.latitude;
markerStart.setPosition(new LatLng(lat, lng));
//markerStart.setPosition(interpolator.interpolate(t, target, replayEnd));
if (t < 1.0) {
//Post again 16ms later == 60 frames per second
handler.postDelayed(this, 32);
} else {
//Animation ended
}
}
});
i++;
}
回答1:
try this code :: first the MarkerAnimation class :
public class MarkerAnimation {
static GoogleMap map;
ArrayList<LatLng> _trips = new ArrayList<>() ;
Marker _marker;
LatLngInterpolator _latLngInterpolator = new LatLngInterpolator.Spherical();
public void animateLine(ArrayList<LatLng> Trips,GoogleMap map,Marker marker,Context current){
_trips.addAll(Trips);
_marker = marker;
animateMarker();
}
public void animateMarker() {
TypeEvaluator<LatLng> typeEvaluator = new TypeEvaluator<LatLng>() {
@Override
public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) {
return _latLngInterpolator.interpolate(fraction, startValue, endValue);
}
};
Property<Marker, LatLng> property = Property.of(Marker.class, LatLng.class, "position");
ObjectAnimator animator = ObjectAnimator.ofObject(_marker, property, typeEvaluator, _trips.get(0));
//ObjectAnimator animator = ObjectAnimator.o(view, "alpha", 0.0f);
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationCancel(Animator animation) {
// animDrawable.stop();
}
@Override
public void onAnimationRepeat(Animator animation) {
// animDrawable.stop();
}
@Override
public void onAnimationStart(Animator animation) {
// animDrawable.stop();
}
@Override
public void onAnimationEnd(Animator animation) {
// animDrawable.stop();
if (_trips.size() > 1) {
_trips.remove(0);
animateMarker();
}
}
});
animator.setDuration(300);
animator.start();
}
and the _latLngInterpolator which is pre-written for you by google developers :
public interface LatLngInterpolator {
public LatLng interpolate(float fraction, LatLng a, LatLng b);
public class Spherical implements LatLngInterpolator {
@Override
public LatLng interpolate(float fraction, LatLng from, LatLng to) {
// http://en.wikipedia.org/wiki/Slerp
double fromLat = toRadians(from.latitude);
double fromLng = toRadians(from.longitude);
double toLat = toRadians(to.latitude);
double toLng = toRadians(to.longitude);
double cosFromLat = cos(fromLat);
double cosToLat = cos(toLat);
// Computes Spherical interpolation coefficients.
double angle = computeAngleBetween(fromLat, fromLng, toLat, toLng);
double sinAngle = sin(angle);
if (sinAngle < 1E-6) {
return from;
}
double a = sin((1 - fraction) * angle) / sinAngle;
double b = sin(fraction * angle) / sinAngle;
// Converts from polar to vector and interpolate.
double x = a * cosFromLat * cos(fromLng) + b * cosToLat * cos(toLng);
double y = a * cosFromLat * sin(fromLng) + b * cosToLat * sin(toLng);
double z = a * sin(fromLat) + b * sin(toLat);
// Converts interpolated vector back to polar.
double lat = atan2(z, sqrt(x * x + y * y));
double lng = atan2(y, x);
return new LatLng(toDegrees(lat), toDegrees(lng));
}
private double computeAngleBetween(double fromLat, double fromLng, double toLat, double toLng) {
// Haversine's formula
double dLat = fromLat - toLat;
double dLng = fromLng - toLng;
return 2 * asin(sqrt(pow(sin(dLat / 2), 2) +
cos(fromLat) * cos(toLat) * pow(sin(dLng / 2), 2)));
}
}
}
and call it on your map activity as :
MarkerAnimation.animateLine(TripPoints,map,MovingMarker,context);
来源:https://stackoverflow.com/questions/23203611/how-to-animate-a-marker-through-an-arraylist-of-latlng-points