I have 3 markers on a Google Map.
Two Markers to show starting and ending points
Here is the code using to draw a Polyline between these two points:
private void polyLine() {
LatLng starting = new LatLng(##.######, ##.######);
LatLng ending = new LatLng(##.######, ##.######);
PolylineOptions line = new PolylineOptions().add(starting, ending);
mGoogleMap.addMarker(new MarkerOptions().position(starting).title("Start"));
mGoogleMap.addMarker(new MarkerOptions().position(ending).title("End"));
mGoogleMap.addPolyline(line);
}
One Marker to show current Location [HUE_ROSE]
And to animate marker to current location using:
#Override
public void onLocationChanged(Location location)
{
Toast.makeText(this, "Location Changed " + location.getLatitude()
+ location.getLongitude(), Toast.LENGTH_LONG).show();
mLastLocation = location;
if (mCurrLocationMarker != null) {
mCurrLocationMarker.remove();
}
LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
if(ourGlobalMarker == null) { // First time adding marker to map
ourGlobalMarker = mGoogleMap.addMarker(new MarkerOptions().position(latLng)
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ROSE)));
MarkerAnimation.animateMarkerToICS(ourGlobalMarker, latLng, new LatLngInterpolator.Spherical());
mGoogleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 18));
} else {
MarkerAnimation.animateMarkerToICS(ourGlobalMarker, latLng, new LatLngInterpolator.Spherical());
mGoogleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 18));
}
}
PROBLEM:
Getting Animating Marker, but right side of Polyline
SOLUTION:
How Can I show Animated Marker on Polyline Path
I tried a lot to find solution for this one, but did not find any thing, share your suggestions.
I am assuming you have 3 marker
1. Source point
2. Destination Point
3. Moving marker
you have to try this way it will help you
private void animateMarkerNew(final LatLng startPosition, final LatLng destination, final Marker marker) {
if (marker != null) {
final LatLng endPosition = new LatLng(destination.latitude, destination.longitude);
final float startRotation = marker.getRotation();
final LatLngInterpolatorNew latLngInterpolator = new LatLngInterpolatorNew.LinearFixed();
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
valueAnimator.setDuration(2000); // duration 3 second
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
try {
float v = animation.getAnimatedFraction();
LatLng newPosition = latLngInterpolator.interpolate(v, startPosition, endPosition);
marker.setPosition(newPosition);
googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder()
.target(newPosition)
.zoom(18f)
.build()));
marker.setRotation(getBearing(startPosition, new LatLng(destination.latitude, destination.longitude)));
} catch (Exception ex) {
//I don't care atm..
}
}
});
valueAnimator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
// if (mMarker != null) {
// mMarker.remove();
// }
// mMarker = googleMap.addMarker(new MarkerOptions().position(endPosition).icon(BitmapDescriptorFactory.fromResource(R.drawable.icon_car)));
}
});
valueAnimator.start();
}
}
Note: marker is mean which marker you want to animate that one.
private interface LatLngInterpolatorNew {
LatLng interpolate(float fraction, LatLng a, LatLng b);
class LinearFixed implements LatLngInterpolatorNew {
#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);
}
}
}
//Method for finding bearing between two points
private float getBearing(LatLng begin, LatLng end) {
double lat = Math.abs(begin.latitude - end.latitude);
double lng = Math.abs(begin.longitude - end.longitude);
if (begin.latitude < end.latitude && begin.longitude < end.longitude)
return (float) (Math.toDegrees(Math.atan(lng / lat)));
else if (begin.latitude >= end.latitude && begin.longitude < end.longitude)
return (float) ((90 - Math.toDegrees(Math.atan(lng / lat))) + 90);
else if (begin.latitude >= end.latitude && begin.longitude >= end.longitude)
return (float) (Math.toDegrees(Math.atan(lng / lat)) + 180);
else if (begin.latitude < end.latitude && begin.longitude >= end.longitude)
return (float) ((90 - Math.toDegrees(Math.atan(lng / lat))) + 270);
return -1;
}
Try out with setting anchor like follows
mDetailPositionMarker = mDetailGoogleMap.addMarker(new MarkerOptions()
.position(newLatLonValue)
.anchor(0.5f, 0.5f)
.rotation(bearingValue)
.flat(true)
.icon(BitmapDescriptorFactory.fromResource(R.drawable.biketopicon)));
And make sure your icon will not be having any padding or margin. Avoid unnecessary space in icon image than the content like shown below.
// Animation handler for old APIs without animation support
private void animateMarkerTo(final Marker marker, final double lat, final double lng) {
final Handler handler = new Handler();
final long start = SystemClock.uptimeMillis();
final long DURATION_MS = 3000;
final Interpolator interpolator = new AccelerateDecelerateInterpolator();
final LatLng startPosition = marker.getPosition();
handler.post(new Runnable() {
#Override
public void run() {
float elapsed = SystemClock.uptimeMillis() - start;
float t = elapsed/DURATION_MS;
float v = interpolator.getInterpolation(t);
double currentLat = (lat - startPosition.latitude) * v + startPosition.latitude;
double currentLng = (lng - startPosition.longitude) * v + startPosition.longitude;
marker.setPosition(new LatLng(currentLat, currentLng));
// if animation is not finished yet, repeat
if (t < 1) {
handler.postDelayed(this, 16);
}
}
});
}
call this method inside onLocationChange method and pass location lat and lang then you will see a magic ;)
Related
private void GetDriverloc(HashMap<String, String> map) {
Call<DriverLocationResToCus> call = apiInterface.GetDriverLoc(map);
System.out.println("enter the currency alert api" + call.request().url());
call.enqueue(new Callback<DriverLocationResToCus>() {
#Override
public void onResponse(Call<DriverLocationResToCus> call, Response<DriverLocationResToCus> response) {
if (response.isSuccessful()) {
assert response.body() != null;
DriverStartLat = response.body().getDriverCurrentLatStart();
DriverStartLng = response.body().getDriverCurrentLngStart();
DriverEndLat = response.body().getDriverCurrentLatEnd();
DriverEndLng = response.body().getDriverCurrentLngEnd();
/here I am getting the driver's location from server. I need to pass the driver lat lnt to the loop and animate the marker accordingly. I tried to pass it directly to the startpostion and endpostion. But the marker flickers continuesly.
Utilities.printV("DriverStartLat", DriverStartLat);
ValueAnimator polylineAnimator = ValueAnimator.ofInt(0, 100);
polylineAnimator.setDuration(2000);
polylineAnimator.setInterpolator(new LinearInterpolator());
polylineAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
List<LatLng> points = greyPolyLine.getPoints();
int percentValue = (int) valueAnimator.getAnimatedValue();
int size = points.size();
int newPoints = (int) (size * (percentValue / 100.0f));
List<LatLng> p = points.subList(0, newPoints);
blackPolyline.setPoints(p);
}
});
polylineAnimator.start();
mHandler = new Handler();
index = -1;
next = 1;
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
if (index < points.size() - 1) {
index++;
next = index + 1;
}
if (index < points.size() - 1) {
startPosition = points.get(index);
endPosition = points.get(next);
}
//when I pass the driver's lat lng directly to the startposition and endposition the marker moves to the new location but it comes back if it does not get new lat lat from the server and also flickers continuously.
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
valueAnimator.setDuration(3000);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
v = valueAnimator.getAnimatedFraction();
lng = v * endPosition.longitude + (1 - v)
* startPosition.longitude;
lat = v * endPosition.latitude + (1 - v)
* startPosition.latitude;
LatLng newPos = new LatLng(lat, lng);
marker.setPosition(newPos);
marker.setAnchor(0.5f, 0.5f);
marker.setRotation(getBearing(startPosition, newPos));
mMap.moveCamera(CameraUpdateFactory
.newCameraPosition
(new CameraPosition.Builder()
.target(newPos)
.zoom(15.5f)
.build()));
}
});
valueAnimator.start();
mHandler.postDelayed(this, 3000);
}
}, 3000);
Utilities.printV("DriverLocationResToCus", "DriverLocationResToCus SUCCESS");
} else {
Utilities.printV("DriverLocationResToCus", "DriverLocationResToCus FAILURE");
}
}
#Override
public void onFailure(Call<DriverLocationResToCus> call, Throwable t) {
}
});
}
//can anyone help me with this pls
Download MarkerAnimation and LatLngInterpolator files from the below links
https://drive.google.com/file/d/1i-pDZYOtf-Vl8m6wnYulGnv3rb9aVMih/view
https://drive.google.com/file/d/1AypW3b6YIX6UtYFFuh1-lx7Id1lt0QqP/view
or Use the below posted code
MarkerAnimation code:
public class MarkerAnimation {
public 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)
public 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();
}
}
LatLngInterpolator Code :
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 is the bit of code that rotates the icon(marker) on the map
private float getBearing(LatLng begin, LatLng end) {
double lat = Math.abs(begin.latitude - end.latitude);
double lng = Math.abs(begin.longitude - end.longitude);
if (begin.latitude < end.latitude && begin.longitude < end.longitude)
return (float) (Math.toDegrees(Math.atan(lng / lat)));
else if (begin.latitude >= end.latitude && begin.longitude < end.longitude)
return (float) ((90 - Math.toDegrees(Math.atan(lng / lat))) + 90);
else if (begin.latitude >= end.latitude && begin.longitude >= end.longitude)
return (float) (Math.toDegrees(Math.atan(lng / lat)) + 180);
else if (begin.latitude < end.latitude && begin.longitude >= end.longitude)
return (float) ((90 - Math.toDegrees(Math.atan(lng / lat))) + 270);
return -1;
}
This is the bit of code that you need to add after getting Lat and Lng from api.
if(marker == null) {
marker = mMap.addMarker(new MarkerOptions().position(endPosition)
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ROSE)));
MarkerAnimation.animateMarkerToGB(marker, endPosition, new LatLngInterpolator.Spherical());
marker.setRotation(getBearing(endPosition, startPosition));
} else {
MarkerAnimation.animateMarkerToICS(marker, endPosition, new LatLngInterpolator.Spherical());
marker.setRotation(getBearing(endPosition, startPosition));
}
Happy coding :)
I am implementing a map navigation application. I get device's current location every 1000 milliseconds and draw a polyline, from the current location to fixed marker point. But when using device inside a vehicle, polyline and current location update not animating like uber or google-map. It's changing suddenly from one point to another.
How to get a smooth animation of the current location change.
you have to try this way it will help you
private void animateMarkerNew(final LatLng startPosition, final LatLng destination, final Marker marker) {
if (marker != null) {
final LatLng endPosition = new LatLng(destination.latitude, destination.longitude);
final float startRotation = marker.getRotation();
final LatLngInterpolatorNew latLngInterpolator = new LatLngInterpolatorNew.LinearFixed();
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
valueAnimator.setDuration(2000); // duration 3 second
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
try {
float v = animation.getAnimatedFraction();
LatLng newPosition = latLngInterpolator.interpolate(v, startPosition, endPosition);
marker.setPosition(newPosition);
googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder()
.target(newPosition)
.zoom(18f)
.build()));
marker.setRotation(getBearing(startPosition, new LatLng(destination.latitude, destination.longitude)));
} catch (Exception ex) {
//I don't care atm..
}
}
});
valueAnimator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
// if (mMarker != null) {
// mMarker.remove();
// }
// mMarker = googleMap.addMarker(new MarkerOptions().position(endPosition).icon(BitmapDescriptorFactory.fromResource(R.drawable.icon_car)));
}
});
valueAnimator.start();
}
}
Note: marker is mean which marker you want to animate that one.
private interface LatLngInterpolatorNew {
LatLng interpolate(float fraction, LatLng a, LatLng b);
class LinearFixed implements LatLngInterpolatorNew {
#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);
}
}
}
//Method for finding bearing between two points
private float getBearing(LatLng begin, LatLng end) {
double lat = Math.abs(begin.latitude - end.latitude);
double lng = Math.abs(begin.longitude - end.longitude);
if (begin.latitude < end.latitude && begin.longitude < end.longitude)
return (float) (Math.toDegrees(Math.atan(lng / lat)));
else if (begin.latitude >= end.latitude && begin.longitude < end.longitude)
return (float) ((90 - Math.toDegrees(Math.atan(lng / lat))) + 90);
else if (begin.latitude >= end.latitude && begin.longitude >= end.longitude)
return (float) (Math.toDegrees(Math.atan(lng / lat)) + 180);
else if (begin.latitude < end.latitude && begin.longitude >= end.longitude)
return (float) ((90 - Math.toDegrees(Math.atan(lng / lat))) + 270);
return -1;
}
I want to rotate marker icon to road direction, as you can see in image it only just placed but its not rotated to road direction.. i've tried below code as far
double lat = 19.205681
double lon = 72.871742
loc.setLatitude(lat);
loc.setLongitude(lon);
Location newLoc = new Location("service Provider");
newLoc.setLongitude(lat);
newLoc.setLongitude(lon);
map.addMarker(new MarkerOptions()
.position(new LatLng(data.getLat(),data.getLon()))
.icon(BitmapDescriptorFactory.fromResource(R.mipmap.ic_pandu_car))
.anchor(0.5f,0.5f)
.rotation(loc.bearingTo(newLoc))
.flat(true));
Note: marker have individual location (ofcource) i dont want to show from-to location bearing ...only individual marker to face on road direction
Thanks you
UPDATE:i wanna set my marker (car) like this Ola app
I have tried your code, first check that is newLoc has bearing or not?
just made some changes as following, you can try it:
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest,
new com.google.android.gms.location.LocationListener() {
#Override
public void onLocationChanged(Location location1) {
if (location1 != null) {
if (currentPositionMarker != null) {
currentPositionMarker.remove();
}
double latitude = location1.getLatitude();
double longitude = location1.getLongitude();
LatLng latLng = new LatLng(latitude, longitude);
int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(activity);
if (status == ConnectionResult.SUCCESS) {
currentPositionMarker = googleMap.addMarker(new MarkerOptions().position(latLng)
.icon(BitmapDescriptorFactory.fromResource(R.drawable.current_position))
.rotation(location1.getBearing()).flat(true).anchor(0.5f, 0.5f)
.alpha((float) 0.91));
} else {
GooglePlayServicesUtil.getErrorDialog(status, activity, status);
}
}
}
});
Following code works perfectly fine.
private double radiansToDegrees(double x) {
return x * 180.0 / Math.PI;
}
double fLat = (Math.PI * past.getLatitude()) / 180.0f;
double fLng = (Math.PI * past.getLongitude()) / 180.0f;
double tLat = (Math.PI * next.getLatitude()) / 180.0f;
double tLng = (Math.PI * next.getLongitude()) / 180.0f;
double degree = radiansToDegrees(Math.atan2(sin(tLng - fLng) * cos(tLat), cos(fLat) * sin(tLat) - sin(fLat) * cos(tLat) * cos(tLng - fLng)));
if (degree >= 0) {
bearing = degree;
} else {
bearing = 360 + degree;
}
marker.rotation((float) bearing);
I want to move a marker from one Latlng to another. I have used this code to move the marker smoothly based on Distance and Time.
public void animateMarker(final LatLng toPosition,
final boolean hideMarker) {
final Handler handler = new Handler();
final long start = SystemClock.uptimeMillis();
Projection proj = googleMap.getProjection();
Point startPoint = proj.toScreenLocation(cabMarker.getPosition());
final LatLng startLatLng = proj.fromScreenLocation(startPoint);
final Interpolator interpolator = new LinearInterpolator();
handler.post(new Runnable() {
#Override
public void run() {
Location prevLoc = new Location("service Provider");
prevLoc.setLatitude(startLatLng.latitude);
prevLoc.setLongitude(startLatLng.longitude);
Location newLoc = new Location("service Provider");
newLoc.setLatitude(toPosition.latitude);
newLoc.setLongitude(toPosition.longitude);
System.out.println("Locations ---- " + prevLoc + "-" + newLoc);
float bearing = prevLoc.bearingTo(newLoc);
long elapsed = SystemClock.uptimeMillis() - start;
float t = interpolator.getInterpolation((float) elapsed
/ CAB_TRACK_INTERVAL);
double lng = t * toPosition.longitude + (1 - t)
* startLatLng.longitude;
double lat = t * toPosition.latitude + (1 - t)
* startLatLng.latitude;
cabMarker.setPosition(new LatLng(lat, lng));
cabMarker.setRotation(bearing + 90);
if (t < 1.0) {
// Post again 16ms later.
handler.postDelayed(this, 16);
} else {
if (hideMarker) {
cabMarker.setVisible(false);
} else {
cabMarker.setVisible(true);
}
}
}
});
}
But the problem is marker wont move on driving directions but in a straight line from A to B. Is it possible to get around 10 road midpoints in between A and B and then and move it along that path?
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)));
Try this code for animation Effect.
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();
}
}
}
}
}
First you have to request from google directions the route from point A to B and it will return a poly line which contain the points you want then call the animation method from each point to point until you have traversed all the points and then only you can make the marker to traverse a certain route when animating from point A to B.
First read about google directions API from google then implement it and continue
I want to implement smooth transition to emulate car marker moving on the map.
Is it possible to animate marker in android map api v2?
None of versions provided worked for me, so I've implemented my custom solution. It provides both - location and rotation animation.
/**
* Method to animate marker to destination location
* #param destination destination location (must contain bearing attribute, to ensure
* marker rotation will work correctly)
* #param marker marker to be animated
*/
public static void animateMarker(Location destination, Marker marker) {
if (marker != null) {
LatLng startPosition = marker.getPosition();
LatLng endPosition = new LatLng(destination.getLatitude(), destination.getLongitude());
float startRotation = marker.getRotation();
LatLngInterpolator latLngInterpolator = new LatLngInterpolator.LinearFixed();
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
valueAnimator.setDuration(1000); // duration 1 second
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override public void onAnimationUpdate(ValueAnimator animation) {
try {
float v = animation.getAnimatedFraction();
LatLng newPosition = latLngInterpolator.interpolate(v, startPosition, endPosition);
marker.setPosition(newPosition);
marker.setRotation(computeRotation(v, startRotation, destination.getBearing()));
} catch (Exception ex) {
// I don't care atm..
}
}
});
valueAnimator.start();
}
}
Rotation computation for specified fraction of animation. Marker is rotated in direction which is closer from start to end rotation:
private static float computeRotation(float fraction, float start, float end) {
float normalizeEnd = end - start; // rotate start to 0
float normalizedEndAbs = (normalizeEnd + 360) % 360;
float direction = (normalizedEndAbs > 180) ? -1 : 1; // -1 = anticlockwise, 1 = clockwise
float rotation;
if (direction > 0) {
rotation = normalizedEndAbs;
} else {
rotation = normalizedEndAbs - 360;
}
float result = fraction * rotation + start;
return (result + 360) % 360;
}
And finally Google's LatLngInterpolator:
private interface LatLngInterpolator {
LatLng interpolate(float fraction, LatLng a, LatLng b);
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);
}
}
}
Try out the below code to animate the marker on Google Map V2.
You need to use the Interpolator class to apply the animation on the Marker and handle it in the Handler for the animation as below:
public void animateMarker(final Marker marker, final LatLng toPosition,
final boolean hideMarker) {
final Handler handler = new Handler();
final long start = SystemClock.uptimeMillis();
Projection proj = mGoogleMapObject.getProjection();
Point startPoint = proj.toScreenLocation(marker.getPosition());
final LatLng startLatLng = proj.fromScreenLocation(startPoint);
final long duration = 500;
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.longitude + (1 - t)
* startLatLng.longitude;
double lat = t * toPosition.latitude + (1 - t)
* startLatLng.latitude;
marker.setPosition(new LatLng(lat, lng));
if (t < 1.0) {
// Post again 16ms later.
handler.postDelayed(this, 16);
} else {
if (hideMarker) {
marker.setVisible(false);
} else {
marker.setVisible(true);
}
}
}
});
}
Just implemented a version, try this
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();
}
LatLngInterpolator class is pre-written by Google guys which you can use as follows:
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)));
}
}
}
Then instantiate an object of the MarkerAnimation class and call the method like this:
MarkerAnimation.animateLine(TripPoints,map,MovingMarker,context);
You just need to add this class and pass a location which you can easily get by using Fusedlocationproviderclient.
public class LocationMoveAnim {
public static void startAnimation(final Marker marker, final GoogleMap googleMap, final LatLng startPosition,
final LatLng endPosition,final GoogleMap.CancelableCallback callback) {
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
int duration = 500;
valueAnimator.setDuration(duration);
final LatLngInterpolatorNew latLngInterpolator = new LatLngInterpolatorNew.LinearFixed();
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(valueAnimator1 -> {
float v = valueAnimator1.getAnimatedFraction();
LatLng newPos = latLngInterpolator.interpolate(v, startPosition, endPosition);
marker.setPosition(newPos);
marker.setAnchor(0.5f, 0.5f);
marker.setRotation((float) bearingBetweenLocations(startPosition, endPosition));
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(newPos,20F));
callback.onFinish();
});
valueAnimator.start();
}
private static double bearingBetweenLocations(LatLng latLng1,LatLng latLng2) {
double PI = 3.14159;
double lat1 = latLng1.latitude * PI / 180;
double long1 = latLng1.longitude * PI / 180;
double lat2 = latLng2.latitude * PI / 180;
double long2 = latLng2.longitude * PI / 180;
double dLon = (long2 - long1);
double y = Math.sin(dLon) * Math.cos(lat2);
double x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLon);
double brng = Math.atan2(y, x);
brng = Math.toDegrees(brng);
brng = (brng + 360) % 360;
return brng;
}
public interface LatLngInterpolatorNew {
LatLng interpolate(float fraction, LatLng a, LatLng b);
class LinearFixed implements LatLngInterpolatorNew {
#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);
}
}
}
}