in iOS, Google Map allow to provide an animation when Marker pop on map.
I'am looking to do the same on Android. So there is nothing to do it or someone know a workaround?
You can animate marker with general Android approach: Animations and Transitions. Use this or that as examples:
private static void animateMarker(final Marker marker, final int current, final LatLng[] line) {
if (line == null || line.length == 0 || current >= line.length) {
return;
}
ObjectAnimator animator = ObjectAnimator.ofObject(marker, property, typeEvaluator, line[current]);
animator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
animateMarker(marker, current + 1, line);
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
animator.setDuration(DURATION);
animator.start();
}
or use libraries, like that.
As per your response from the server, you receive/extract the latitude and longitude.
//call this method for adding marker with lat and long
public void addmarker(){
LatLng marker = new LatLng(double lat, double long);
googleMap.addMarker(new MarkerOptions().position(marker)
.title("My title"));
googleMap.moveCamera(CameraUpdateFactory.newLatLng(marker));
// now the marker is set
// add a delay of 100-200 ms and start you animation (delay for failsafe)
}
Related
I'm trying to animate a Polyline on MapboxMap using ValueAnimator.
I've found many solutions but those were on google maps, and tried to implements the logic but no luck, here is the code I've written so far:
public static void addHistoryLine(final MapboxMap mapboxMap, final List<LatLng> cords) {
final Polyline backGroundPolyline;
final Polyline foreGroundPolyline;
final ValueAnimator polylineAnimator;
final int size = cords.size();
final PolylineOptions polylineOptions = new PolylineOptions();
polylineOptions.width(3);
polylineOptions.color(Color.BLUE);
polylineOptions.addAll(cords);
backGroundPolyline = mapboxMap.addPolyline(polylineOptions);
final PolylineOptions foreGroundOptions = new PolylineOptions();
foreGroundOptions.width(3);
foreGroundOptions.color(Color.GREEN);
foreGroundPolyline = mapboxMap.addPolyline(foreGroundOptions);
polylineAnimator = ValueAnimator.ofInt(0, size);
polylineAnimator.setInterpolator(new LinearInterpolator());
polylineAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
try {
int val = (int) valueAnimator.getAnimatedValue();
Log.e("Animated Val: ", "value is: " + val);
List<LatLng> points = backGroundPolyline.getPoints();
int Pointsize = points.size();
int newPoints = (int) (size * (val / Pointsize));
List<LatLng> p = points.subList(val, newPoints);
foreGroundPolyline.setPoints(p);
} catch (Exception ex) {
ex.printStackTrace();
}
}
});
polylineAnimator.setDuration(10000);
polylineAnimator.start();
polylineAnimator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
Log.e("Animation", "Animation Start");
}
#Override
public void onAnimationEnd(Animator animation) {
Log.e("Animation", "Animation End");
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
}
My idea here is to draw a background polyline and then redraw a new polyline over it by calculating its point and Value of ValueAnimator. But I'm not able to do so. Any idea how can i calculate those new points to set intoforeGroundPolyline`?
I am trying to achieve this loading with Maps. I have tried loading my animation after the Google Map is created and location is found. But the location loading starts after the animation is completed. How can I achieve the reveal animation after the map camera has navigated to the user's location.
I am not using Splash Screen. The animation code is within the MapsActivity.
private void setupRevealBackground(){
final int revealX = (int) (mBackgroundView.getX() + mBackgroundView.getWidth() / 2);
final int revealY = (int) (mBackgroundView.getY() + mBackgroundView.getHeight() / 2);
ViewTreeObserver viewTreeObserver = mBackgroundView.getViewTreeObserver();
if (viewTreeObserver.isAlive()) {
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
revealActivity(revealX, revealY);
mBackgroundView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
}
}
protected void revealActivity(int x, int y) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
float finalRadius = (float) (Math.max(mBackgroundView.getWidth(), mBackgroundView.getHeight()) * 1.1);
// create the animator for this view (the start radius is zero)
Animator circularReveal = ViewAnimationUtils.createCircularReveal(mBackgroundView, x, y, 0, finalRadius);
circularReveal.setDuration(400);
circularReveal.setInterpolator(new AccelerateInterpolator());
// make the view visible and start the animation
circularReveal.start();
circularReveal.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
}
#Override
public void onAnimationEnd(Animator animation) {
mBackgroundView.setVisibility(View.GONE);
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
} else {
finish();
}
}
I am updating the location after the location is found Preference Change Listener.
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (key.equals(Constants.LatitudePref)) {
Latitude = LocationResultHelper.getSavedLatitude(sharedPreferences);
Longitude = LocationResultHelper.getSavedLongitude(sharedPreferences);
if (mPickUpLatLng == null){
updateMarker(new LatLng(Latitude, Longitude));
}
} else if (key.equals(Constants.KEY_LOCATION_UPDATES_REQUESTED)) {
LocationRequestHelper.getRequesting(this);
}
}
This is my updateMarker Method after location is found
private void updateMarker(LatLng userLocation) {
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(userLocation, 16));
setupRevealBackground();
}
I have tried adding setupRevealBackground() method in the CameraIdleListener but the method is never called.
As indicated in this answer you can use OnMapLoadedCallback
When you have a reference to the map set the call back.
mMap.setOnMapLoadedCallback(this);
When the onMapLoaded event fires take the snapshot.
#Override
public void onMapLoaded() {
// Here you can display your map with animation
}
I was referring to this code snippet to animate marker on Google Maps, which uses ObjectAnimator. I call the method again once it ends, providing it with new value from a list.
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();
}
ObjectAnimator is best suited for my needs, and I would like to know if I can smoothly rotate a (car) marker using it.
I am attempting to animate markers on a Google Map. The issue that I am running into is how the markers are behaving when it is time for them to animate. The markers are moving along a given set of points, but they start shaking rather violently, or they will move along a set path and appear to be rubberbanding, or jumping back to the original start position.
Has anyone dealt with this issue before? and if so, how did you fix it? I am currently using a somewhat modified version of code that was provided by Google devs to handle animation.
UPDATE: I believe the issue is caused by trying to run many animations simultaneously on a given Marker. This is causing the marker to bounce back and forth between all the new/old positions.
Here is the code that handles the Animation calls, the method is passed a list of LatLngs which represent the path the marker should follow.
public void animateMarker(String key, List<LatLng> latlngList) {
AnimateCarObj animateCarObj = animateCarObjMap.get(key);
Marker marker = markersHashMap.get(key);
if (marker != null) {
LatLng prev = new LatLng(0, 0);
for (LatLng latlng : latlngList) {
if (!(latlng.equals(prev))) {
try {
LatLngInterpolator latlonInter = new LinearFixed();
latlonInter.interpolate(1, animateCarObj.getGps1(), latlng);
MarkerAnimation.animateMarker(latlngList.size(), marker, latlng, latlonInter);
prev = latlng;
} catch (Exception e) {
Log.e(TAG, "EXCEPTION: " + e.getMessage());
e.printStackTrace();
}
}
}
}
}
MarkerAnimation Class, I modified this class to take an Integer value called "steps", this is so that the animation will pass through all the points at an even pace regardless of how many points are returned through a request. In this example, it uses a default value of 3, multiplies it by 10000 ms, and than divides it by the step count.
public class MarkerAnimation {
public static void animateMarker(int steps, final Marker marker, final LatLng finalPosition,
final LatLngInterpolator latLngInterpolator) {
if (marker == null || finalPosition == null || latLngInterpolator == null) { return; }
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR1) {
animateMarkerToGB(steps, marker, finalPosition, latLngInterpolator);
} else {
animateMarkerToICS(steps, marker, finalPosition, latLngInterpolator);
}
}
public static void animateMarkerToGB(int steps, 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 = (CarListStore.DEFAULT_ALIVE_COUNT * 10000) / steps;
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)
public 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(int steps, 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((CarListStore.DEFAULT_ALIVE_COUNT * 10000) / steps);
animator.start();
}
}
You are making Asynchronous calls right now and since you have multiple animation on maker you are facing jitters.
Use synchronized method instead i.e [valueAnimator][1] - you have it commented out in your code. Watch this video in the docs, it explains why and when to use it.
Hope it helped!
My method is to schedule a Runnable using handler such that it can have some callback to call to notify animation is complete. Maintain a linked list for queueing marker position as soon as you get OnComplete callback from last animation handler delayed runnable pop the next latlng object from the queue and run the animation.
In each animation method for ICS & HC after animator.start() register delayed runnable using handler.postDelayed() where the delay is exact duration of the animation
How would one fade in and out a GoogleMap marker?
This is how I add a marker to the Map:
marker = map.addMarker(new MarkerOptions()
.position(point)
.title(title)
.snippet(text)
.icon(BitmapDescriptorFactory.fromResource(R.drawable.marker))
);
A much simpler and cleaner solution is to just use the standard ObjectAnimator which was introduced in Android SDK 11.
Fading in is literally a one-liner:
ObjectAnimator.ofFloat(marker, "alpha", 0f, 1f).setDuration(500).start();
Fading out requires a bit more code to properly remove the marker once the animation completes:
Animator animator = ObjectAnimator.ofFloat(marker, "alpha", 1f, 0f);
animator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationEnd(Animator animator) {
marker.remove();
}
#Override public void onAnimationStart(Animator animator) {}
#Override public void onAnimationCancel(Animator animator) {}
#Override public void onAnimationRepeat(Animator animator) {}
});
animator.setDuration(500).start();
With Google Play services 4.0+ you can use Marker.setAlpha in conjunction with Handler that posts some Runnable every few milliseconds.
The code will be similar to my answer here Drop marker slowly from top of screen to location on android map V2. Just setAlpha instead of setPosition and you are on your way home.
use this code for fade in and out
map.moveCamera(CameraUpdateFactory.newLatLngZoom(position, 15));
map.animateCamera(CameraUpdateFactory.zoomTo(15), 2000, null);
Here is a more complete solution specifically for Fade In when adding a marker. Something to note is the requestNumber. this is useful if you're loading items while moving the map. Just increment it on every service call or remove it if you don't need it.
public void fadeInMarker(Activity activity,final GoogleMap map, final MarkerOptions markerOptions, final long duration,final int requestNumber){
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
if (currentRequestNumber != requestNumber){
return;
}
markerOptions.alpha(0);
final Marker marker = map.addMarker(markerOptions);
final AccelerateInterpolator accelartor = new AccelerateInterpolator();
final Long startTime = SystemClock.uptimeMillis();
final Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run() {
float diff = SystemClock.uptimeMillis() - startTime;
float alpha = accelartor.getInterpolation(diff / duration);
if (alpha < 1) {
handler.postDelayed(this, 10);
}
else{
alpha = 1;
}
if (currentRequestNumber == requestNumber){
marker.setAlpha(alpha);
}
}
});
}
});
}