i am using google maps v2. i have a marker on map, this marker changes rotation every while. I want to animate the rotation of my maker to rotate smoothly. Can anyone help please
8 Answers
That's mine implementation of smooth marker movement with maker image rotation (when it's set to FLAT [important]). The marker is moved to the requested location smoothly plus it's rotated to the requested degree with a proper direction. For example, when moving from 5deg to 355deg it moves anticlockwise, when 355deg to 5deg it moves clockwise.
public void animateMarker(final Location location)
{
if (myMarkerLOC != null) {
final LatLngInterpolator latLngInterpolator = new LatLngInterpolator.LinearFixed();
ValueAnimator valueAnimator = new ValueAnimator();
final LatLng startPosition = myMarkerLOC.getPosition();
final float startRotation = myMarkerLOC.getRotation();
final float angle = 180 - Math.abs(Math.abs(startRotation - location.getBearing()) - 180);
final float right = WhichWayToTurn(startRotation, location.getBearing());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
try {
if (myMarkerLOC == null) // oops... destroying map during animation...
{
return;
}
float v = animation.getAnimatedFraction();
LatLng newPosition = latLngInterpolator.interpolate(v, startPosition, PositionUtil.toLatLng(location));
float rotation = startRotation + right * v * angle;
myMarkerLOC.setRotation((float) rotation);
myMarkerLOC.setPosition(newPosition);
} catch (Exception ex) {
// I don't care atm..
}
}
});
valueAnimator.setFloatValues(0, 1);
valueAnimator.setDuration(300);
valueAnimator.start();
}
}
private float WhichWayToTurn(float currentDirection, float targetDirection)
{
float diff = targetDirection - currentDirection;
if (Math.abs(diff) == 0)
{
return 0;
}
if(diff > 180)
{
return -1;
}
else
{
return 1;
}
}
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);
}
}
}
Missing implementation of "toLatLong" method:
public static LatLng toLatLng(final Location location)
{
return new LatLng(location.getLatitude(), location.getLongitude());
}
I hope that helps.

- 500
- 1
- 12
- 24
-
What is PositionUtil? – The_Martian Feb 16 '16 at 04:53
-
I think the PositionUtil is a custom class that has a method to convert Location object to LatLng object. Please correct me if I am wrong. This simply draws multiple markers instead of animating the marker. Can you explain to why is this happening? – The_Martian Feb 16 '16 at 05:13
-
1@The_Martian: PositionUtil is my util class for various calculcations. In this case "PositionUtil.toLatLng" is a static method that converts location to LatLong. So yes, you're right :) – user007 Feb 16 '16 at 20:41
-
i am unable to make my marker rotate with the direction – Nishant Rajput Sep 29 '16 at 13:25
-
what do you mean? If the Location contains proper Bearing it will just rotate to that direction. – user007 Sep 30 '16 at 09:55
-
this sounds to be more simple, I like it – ilidiocn Nov 21 '21 at 08:10
boolean isRotating = false;
public void rotateMarker(final Marker marker, final float toRotation) {
if(!isRotating) {
isRotating = true;
final Handler handler = new Handler();
final long start = SystemClock.uptimeMillis();
final float startRotation = marker.getRotation();
final long duration = 1000;
float deltaRotation = Math.abs(toRotation - startRotation) % 360;
final float rotation = (deltaRotation > 180 ? 360 - deltaRotation : deltaRotation) *
((toRotation - startRotation >= 0 && toRotation - startRotation <= 180) || (toRotation - startRotation <= -180 && toRotation - startRotation >= -360) ? 1 : -1);
final LinearInterpolator interpolator = new LinearInterpolator();
handler.post(new Runnable() {
@Override
public void run() {
long elapsed = SystemClock.uptimeMillis() - start;
float t = interpolator.getInterpolation((float) elapsed / duration);
marker.setRotation((startRotation + t * rotation) % 360);
if (t < 1.0) {
// Post again 16ms later.
handler.postDelayed(this, 16);
} else {
isRotating = false;
}
}
});
}
}
This is how I rotate the marker, I don't know this is the best code or not. But I think it will prevent wrong rotation. EDIT: Add var isRotating (Thanks @Trần Văn Huy)

- 91
- 1
- 4
-
1
-
@ChintanShah Look like this angle calculation provide `rotation` with the wrong value (sign). For example -41 instead 41 or 54.5 instead -54.5. Did you fix it? – ViT-Vetal- Feb 20 '19 at 10:00
-
***Important note*** `toRotation` should be between -180 and 180. For example you can use `(float)SphericalUtil.computeHeading(startPosition, endPosition)` this method return value within the range [-180,180) http://googlemaps.github.io/android-maps-utils/javadoc/com/google/maps/android/SphericalUtil.html#computeHeading-LatLng-LatLng- – ViT-Vetal- Feb 20 '19 at 10:39
-
@ViT-Vetal- I have not checked for the values you have provided but it was working fine for me when I implemented in my project one year ago. – Chintan Shah Feb 21 '19 at 04:33
-
@ViT-Vetal- sry bro, I assume that you misinterpret about my "sign", i have update my answer with detail explanation. Thank you – Bhagaskara Feb 24 '19 at 05:46
-
@BhagaskaraLiancer try this kml file. Init rotation = 0; https://justpaste.it/6jsrm (first value - longitude) – ViT-Vetal- Mar 11 '19 at 09:48
static public void rotateMarker(final Marker marker, final float toRotation, GoogleMap map) {
final Handler handler = new Handler();
final long start = SystemClock.uptimeMillis();
final float startRotation = marker.getRotation();
final long duration = 1555;
final Interpolator interpolator = new LinearInterpolator();
handler.post(new Runnable() {
@Override
public void run() {
long elapsed = SystemClock.uptimeMillis() - start;
float t = interpolator.getInterpolation((float) elapsed / duration);
float rot = t * toRotation + (1 -t) * startRotation;
marker.setRotation(-rot > 180 ? rot/2 : rot);
if (t < 1.0) {
// Post again 16ms later.
handler.postDelayed(this, 16);
}
}
});
}
i have managed to do it :)

- 1,061
- 3
- 12
- 26
-
2
-
2That actually doesn't work well when passing moving between left and right sides of the northern hemisphere - like: 350deg -> 10deg - it's not moving clockwise but anticlockwise or in opposite 10deg -> 350deg - it's not moving anticlockwise but clockwise which is wrong. It should take the shorter turn. – user007 Dec 11 '15 at 07:50
-
-
-
@ViT-Vetal- well, yeah, see my answer above @ https://stackoverflow.com/questions/28967821/animate-the-rotation-of-the-marker-in-google-map-v2/34219408#34219408 I use that implementation in my app. – user007 Feb 03 '19 at 21:13
With @Bhagaskara Liancer answer.Add var isMarkerRotating with help marker rotate smoothly.
private boolean isMarkerRotating = false;
public void rotateMarker(final Marker marker, final float toRotation) {
if(!isMarkerRotating){
final Handler handler = new Handler();
final long start = SystemClock.uptimeMillis();
final float startRotation = marker.getRotation();
final long duration = 1000;
float deltaRotation = Math.abs(toRotation - startRotation) % 360;
final float rotation = (deltaRotation > 180 ? 360 - deltaRotation : deltaRotation) * ((toRotation - startRotation >= 0 && toRotation - startRotation <= 180)
|| (toRotation - startRotation <=-180 && toRotation- startRotation>= -360) ? 1 : -1);
final LinearInterpolator interpolator = new LinearInterpolator();
handler.post(new Runnable() {
@Override
public void run() {
isMarkerRotating = true;
long elapsed = SystemClock.uptimeMillis() - start;
float t = interpolator.getInterpolation((float) elapsed / duration);
marker.setRotation((startRotation + t* rotation)%360);
if (t < 1.0) {
// Post again 16ms later.
handler.postDelayed(this, 16);
}else {
isMarkerRotating = false;
}
}
});
}
}

- 16,914
- 6
- 65
- 97

- 21
- 2
Here is the simple example You can use the following MarkerAnimation class for animating marker with rotation.
import android.graphics.Point;
import android.location.Location;
import android.os.Handler;
import android.os.SystemClock;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import com.gogrocerycart.settings.Constants;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.Projection;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
/**
* Created by Vinil Chandran on 7/6/18.
*/
public class MarkerAnimation {
private static Location fromPosition;
private static float angle = 0;
public static void move(GoogleMap mMap, final Marker marker, final Location toPosition) {
if (fromPosition != null && marker != null && toPosition != null) {
final Handler handlerRotation = new Handler();
final long startAngle = SystemClock.uptimeMillis();
final float startRotation = marker.getRotation();
final long durationRotation = 300;
final Interpolator interpolatorRotation = new LinearInterpolator();
float bearing = fromPosition.bearingTo(toPosition);
Print.e("Bearing:" + bearing);
angle = bearing<0?(360+bearing):bearing;
angle = angle%360f;
Print.e("Angle:" + angle);
handlerRotation.post(new Runnable() {
@Override
public void run() {
long elapsed = SystemClock.uptimeMillis() - startAngle;
float t = interpolatorRotation.getInterpolation((float) elapsed / durationRotation);
float rot = t * angle + (1 - t) * startRotation;
float mAngle = -rot > 180 ? rot / 2 : rot;
marker.setRotation(mAngle);
if (t < 1.0) {
handlerRotation.postDelayed(this, 16);
} else {
final Handler handler = new Handler();
final long start = SystemClock.uptimeMillis();
Projection projection = mMap.getProjection();
Point startPoint = projection.toScreenLocation(marker.getPosition());
final LatLng startLatLng = projection.fromScreenLocation(startPoint);
final long duration = Constants.LOCATION_REQUEST_INTERVAL;
final Interpolator interpolator = new LinearInterpolator();
handler.post(new Runnable() {
@Override
public void run() {
long elapsed = SystemClock.uptimeMillis() - start;
float t = interpolator.getInterpolation((float) elapsed
/ duration);
double lng = t * toPosition.getLongitude() + (1 - t)
* startLatLng.longitude;
double lat = t * toPosition.getLatitude() + (1 - t)
* startLatLng.latitude;
marker.setPosition(new LatLng(lat, lng));
if (t < 1.0) {
// Post again 16ms later.
handler.postDelayed(this, 16);
}
}
});
}
}
});
}
fromPosition = toPosition;
}
}
Just call the following code for moving the marker when the location is changed.
if (carMarker != null) {
MarkerAnimation.move(mMap,carMarker, location);
}

- 1,563
- 1
- 19
- 33
Had the same problem, in my case I used ValueAnimator
static public void rotateMarker(final Marker marker, final float toRotation) {
ValueAnimator animator = ValueAnimator.ofFloat(marker.getRotation(), toRotation);
animator.setDuration(duration);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float rotate = Float.parseFloat(animation.getAnimatedValue().toString());
marker.setRotation(rotate);
}
});
animator.start();
}

- 1,929
- 1
- 17
- 30
The answer from Alexandr Kolesnik seems to be the most simple.
Here's a Kotlin extension version of it.
You can pass in an interpolator to avoid a little thrash.
fun Marker.animateRotation(toRotation: Float, interpolator: TimeInterpolator? = AccelerateDecelerateInterpolator()) {
val animator = ValueAnimator.ofFloat(rotation, toRotation)
animator.duration = 500
animator.interpolator = interpolator
animator.addUpdateListener {
rotation = it.animatedValue as? Float ?: return@addUpdateListener
}
animator.start()
}

- 2,804
- 1
- 32
- 37
You would want to use MarkerOption rotation method
public MarkerOptions rotation (float rotation)
Sets the rotation of the marker in degrees clockwise about the marker's anchor point. The axis of rotation is perpendicular to the marker. A rotation of 0 corresponds to the default position of the marker. When the marker is flat on the map, the default position is North aligned and the rotation is such that the marker always remains flat on the map. When the marker is a billboard, the default position is pointing up and the rotation is such that the marker is always facing the camera. The default value is 0.
Returns the object for which the method was called, with the new rotation set.

- 8,199
- 2
- 15
- 17