/* Copyright 2013 Google Inc. | |
Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0.html */ | |
package com.example.latlnginterpolation; | |
import android.animation.ObjectAnimator; | |
import android.animation.TypeEvaluator; | |
import android.animation.ValueAnimator; | |
import android.annotation.TargetApi; | |
import android.os.Build; | |
import android.os.Handler; | |
import android.os.SystemClock; | |
import android.util.Property; | |
import android.view.animation.AccelerateDecelerateInterpolator; | |
import android.view.animation.Interpolator; | |
import com.google.android.gms.maps.model.LatLng; | |
import com.google.android.gms.maps.model.Marker; | |
public class MarkerAnimation { | |
static void animateMarkerToGB(final Marker marker, final LatLng finalPosition, final LatLngInterpolator latLngInterpolator) { | |
final LatLng startPosition = marker.getPosition(); | |
final Handler handler = new Handler(); | |
final long start = SystemClock.uptimeMillis(); | |
final Interpolator interpolator = new AccelerateDecelerateInterpolator(); | |
final float durationInMs = 3000; | |
handler.post(new Runnable() { | |
long elapsed; | |
float t; | |
float v; | |
@Override | |
public void run() { | |
// Calculate progress using interpolator | |
elapsed = SystemClock.uptimeMillis() - start; | |
t = elapsed / durationInMs; | |
v = interpolator.getInterpolation(t); | |
marker.setPosition(latLngInterpolator.interpolate(v, startPosition, finalPosition)); | |
// Repeat till progress is complete. | |
if (t < 1) { | |
// Post again 16ms later. | |
handler.postDelayed(this, 16); | |
} | |
} | |
}); | |
} | |
@TargetApi(Build.VERSION_CODES.HONEYCOMB) | |
static void animateMarkerToHC(final Marker marker, final LatLng finalPosition, final LatLngInterpolator latLngInterpolator) { | |
final LatLng startPosition = marker.getPosition(); | |
ValueAnimator valueAnimator = new ValueAnimator(); | |
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { | |
@Override | |
public void onAnimationUpdate(ValueAnimator animation) { | |
float v = animation.getAnimatedFraction(); | |
LatLng newPosition = latLngInterpolator.interpolate(v, startPosition, finalPosition); | |
marker.setPosition(newPosition); | |
} | |
}); | |
valueAnimator.setFloatValues(0, 1); // Ignored. | |
valueAnimator.setDuration(3000); | |
valueAnimator.start(); | |
} | |
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) | |
static void animateMarkerToICS(Marker marker, LatLng finalPosition, final LatLngInterpolator latLngInterpolator) { | |
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, finalPosition); | |
animator.setDuration(3000); | |
animator.start(); | |
} | |
} |
/* Copyright 2013 Google Inc. | |
Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0.html */ | |
package com.example.latlnginterpolation; | |
import com.google.android.gms.maps.model.LatLng; | |
import static java.lang.Math.asin; | |
import static java.lang.Math.atan2; | |
import static java.lang.Math.cos; | |
import static java.lang.Math.pow; | |
import static java.lang.Math.sin; | |
import static java.lang.Math.sqrt; | |
import static java.lang.Math.toDegrees; | |
import static java.lang.Math.toRadians; | |
public interface LatLngInterpolator { | |
public LatLng interpolate(float fraction, LatLng a, LatLng b); | |
public class Linear implements LatLngInterpolator { | |
@Override | |
public LatLng interpolate(float fraction, LatLng a, LatLng b) { | |
double lat = (b.latitude - a.latitude) * fraction + a.latitude; | |
double lng = (b.longitude - a.longitude) * fraction + a.longitude; | |
return new LatLng(lat, lng); | |
} | |
} | |
public class LinearFixed implements LatLngInterpolator { | |
@Override | |
public LatLng interpolate(float fraction, LatLng a, LatLng b) { | |
double lat = (b.latitude - a.latitude) * fraction + a.latitude; | |
double lngDelta = b.longitude - a.longitude; | |
// Take the shortest path across the 180th meridian. | |
if (Math.abs(lngDelta) > 180) { | |
lngDelta -= Math.signum(lngDelta) * 360; | |
} | |
double lng = lngDelta * fraction + a.longitude; | |
return new LatLng(lat, lng); | |
} | |
} | |
public class Spherical implements LatLngInterpolator { | |
/* From github.com/googlemaps/android-maps-utils */ | |
@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))); | |
} | |
} | |
} |
This comment has been minimized.
This comment has been minimized.
Hey @slightfoot - nice work! That's pretty neat. Sorry, I didn't see your comment til now. I should have elaborated, though - the paints in Android's UI thread are actually run in parallel to the paints in the OpenGL thread in the Maps API. So, while HC's Animators and the code you wrote provide smooth animation for regular views, we're still stuck with slightly jerky animation for Markers and other things rendered on the Maps API. |
This comment has been minimized.
This comment has been minimized.
Sorry, I only just noticed this comment. Thanks for elaborating. So regular views and GL views are rendered in parallel to each other. So this means you could have 2 rendering passes of the regular views whilst GL render pass might skip frames because it takes longer on older hardware? Could you not add a relative time value to the Marker.setPosition so as-to to provide a smooth transition in the GL renderer? |
This comment has been minimized.
This comment has been minimized.
Android studio is telling me that the method ValueAnimator.getAnimatedFraction() is not available on HONEYCOMB, only HONEYCOMB_MR1 and up. |
This comment has been minimized.
This comment has been minimized.
In the animation methods, we have passed a LatLngInterpolator and called its interpolate method - but which of the three interpolation methods (Linear, LinearFixed, Spherical) will this invoke? |
This comment has been minimized.
This comment has been minimized.
Hi, broady thanks for your support. I want to delete just one of my maps items (maybe a marker), I dont want yo clean all my map only remove that element using API V2. Its posible? |
This comment has been minimized.
This comment has been minimized.
Hi @aliceresponde , you can remove a marker by calling marker.remove(). |
This comment has been minimized.
This comment has been minimized.
@broady Thanks for the code. I am trying to implement animation of markers, But for some reason the markers flicker and appear at the centre of the Map when animated from one Location to another. Do you know the reason why that may happen ? |
This comment has been minimized.
This comment has been minimized.
Hi, Broady thank u so much for your support. I have tried your code (animateMarkerToGB,animateMarkerToHC,animateMarkerToICS) for animating marker from one point to other point. Markers are doing smooth transition but after some time markers start stuttering. Can you please suggest a fix or if you had already fixed it then can you please update it. Also if anyone on this forum has done some fix then please let me know. Thanks |
This comment has been minimized.
This comment has been minimized.
Hi, I want to animate markers, but on a given lineString of geoPoints. For this I've tried below approach.
|
This comment has been minimized.
This comment has been minimized.
Here is my approach for animate marker along a path. It is also supported that origin and destination marker point is outside path. In that case first movement is to reach nearest point in path in line. Same thing happens at the end when last point is outside path.
|
This comment has been minimized.
This comment has been minimized.
@banny310 Is Path Interpolator useful for two points as well ? |
This comment has been minimized.
This comment has been minimized.
Hei, is it possible to animate Polyline? I have a polyline between my current location and a marker. The marker will get new position every 3 seconds. I get the marker animation working with this method
It's cool and smooth, like it |
This comment has been minimized.
This comment has been minimized.
i'm trying this on the Jelly Bean API but it doesn't seem to work i get an error on the final LatLngInterpolator and on the return latLngInterpolator.interpolate part does anyone know how can i repair this? |
This comment has been minimized.
This comment has been minimized.
Thanks It's Working Grate!!! /*Add Marker */ I was trying to set position of marker and then calling above animation after spending some time on this found the bug and solved it! Can anyone help me use marker as GIF image, or kind of animation apply on marker. Thanks. |
This comment has been minimized.
This comment has been minimized.
Hello benny, |
This comment has been minimized.
This comment has been minimized.
I am interested in the MarkerAnimation routine. I have a version of it working, but I would like to be able to control it such as Pause, Restart and Stop. I have tried obvious techniques (such as introducing code from outside the loop) but these cause the app to crash. I think this is because it is within the run loop and only static variables are in the loop and they cannot be altered. Regards |
This comment has been minimized.
This comment has been minimized.
Following my comments 17 hours ago, I have successfully enabled Start, Pause, Restart, Stop by placing the control code at the start of the Runnable() section rather than deeper in the run() section. However, I cannot start a new animation until the app is closed and restarted. The app crashes. I've tried handler.removeCallbacksAndMessages(null) but this does not help. |
This comment has been minimized.
This comment has been minimized.
Problem solved. I hadn't reinitialized a variable. |
This comment has been minimized.
This comment has been minimized.
Is there anyone who guide me about LatLngUtils class. I did't found |
This comment has been minimized.
This comment has been minimized.
HI guys! The problem is: |
This comment has been minimized.
This comment has been minimized.
please give one example project i didn't understand Interpolator |
This comment has been minimized.
This comment has been minimized.
have try to use new LatLngInterpolator.Spherical() & animateMarkerToICS, and got marker far away from the polyline, can any one help me in that. I want to build a map like Uber/Ola App on which i can track my device on traveling path. |
This comment has been minimized.
This comment has been minimized.
@banny310 can you provide LatLngUtils class? |
This comment has been minimized.
This comment has been minimized.
@vimlesh |
This comment has been minimized.
This comment has been minimized.
@Ankitj13 Did you find solution? i have the same requirement. Let me know if you found the solution. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
same problem here, any solution? |
This comment has been minimized.
Hey broady,
You mentioned on the video how you cannot sync the paint of the markers with that of the framework so you just have to use 16ms delayed posted runnables. Here is a version that does not contain that issue on pre-HC.
Example of synchronized animated markers on Android 2.3 and up. (Android without Object Animators or JB's Choreographer.)
https://gist.github.com/slightfoot/6444918
Will also comment on YT if you want to up it,
Simon