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.
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
}
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)
}
I can't get the circular reveal animation to work.
I think I checked the most obvious things:
It starts, width and height are > 0 and it is visible, no Exception..
I load some data from the internet and display it in the view(fab)
The animation should only play after the download finishes.
TmdbHelper helper = new TmdbHelper();
helper.getMovieById(id, "en", new TmdbHelper.ResultListener() {
#Override
public void onResultReceived(JSONObject result) {
// called when finished downloading
try {
String rating = result.getString("vote_average");
AnimationHelper.circularReveal(fab, 500, 0);
fab.setText(rating);
} catch (JSONException e) {
e.printStackTrace();
}
}
});
AnimationHelper:
public static void circularReveal(final View view, final long duration, long startDelay) {
// get the center for the clipping circle
int cx = (view.getLeft() + view.getRight()) / 2;
int cy = (view.getTop() + view.getBottom()) / 2;
// get the final radius for the clipping circle
int finalRadius = Math.max(view.getWidth(), view.getHeight());
// create the animator for this view (the start radius is zero)
Animator anim =
ViewAnimationUtils.createCircularReveal(view, cx, cy, 0, finalRadius);
anim.setDuration(duration);
anim.setStartDelay(startDelay);
anim.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
view.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationEnd(Animator animation) {
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {}
});
// make the view visible and start the animation
anim.start();
}
I use the circular reveal animation in other parts like this to make sure the view is attached, and it works:
headerContainer.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
headerContainer.getViewTreeObserver().removeOnGlobalLayoutListener(this);
AnimationHelper.circularReveal(headerContainer, 500, 200);
}
});
Perhaps you should erase this line inside your onResultRecieved():
fab.setVisibility(View.VISIBLE);
My assumption is that your circular reveal method is working just fine. It is because of you have made the FAB visible before the animation even begin, you can't see it in action.
As an addition, those lines you've shown which is working doesn't have fab.setVisibility(View.VISIBLE) called anywhere in it.
1st Approach:
Try Transition Listener.
getWindow().getSharedElementExitTransition().addListener(new Transition.TransitionListener() {
#Override
public void onTransitionStart(Transition transition) {
}
#Override
public void onTransitionEnd(Transition transition) {
}
#Override
public void onTransitionCancel(Transition transition) {
}
#Override
public void onTransitionPause(Transition transition) {
}
#Override
public void onTransitionResume(Transition transition) {
}
});
2nd Approach: Try setting start delay and listener to the reveal animation and when animation starts then set the view visible
if (Build.VERSION.SDK_INT >= 21) {
Animator anim = ViewAnimationUtils.createCircularReveal(viewRoot, cx, cy, 0, finalRadius);
anim.setStartDelay(300);
anim.setDuration(1000);
anim.setInterpolator(new DecelerateInterpolator());
anim.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
viewRoot.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationEnd(Animator animation) {
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
anim.start();
}
}
#Override
public void onAnimationCancel(Animator animation) {
}
#Override
public void onAnimationRepeat(Animator animation) {
}
});
anim.start();
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);
}
}
});
}
});
}