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`?
Related
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 try to cluster some points in my application map, It work prefect for first time and data clustered but when try to update the list again with new data not change happen and clusters still exist I try to use clearItems(), clear() map but no change happen the following is my code for it can any one help please.
Code for map
((SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map)).getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(final GoogleMap googleMap) {
mMap = googleMap;
LatLngBounds ADELAIDE = new LatLngBounds(
new LatLng(16.57946, 35.69014), new LatLng(31.67252, 50.20833));
mMap.setLatLngBoundsForCameraTarget(ADELAIDE);
final LatLng location = new LatLng(mDefaultLat, mDefaultLng);
mClusterManager = new ClusterManager<>(getContext(), mMap);
mClusterManager.setRenderer(new ClusterRenderer(getContext(), mMap, mClusterManager));
final CameraPosition[] mPreviousCameraPosition = {null};
mMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
#Override
public void onCameraIdle() {
CameraPosition position = googleMap.getCameraPosition();
mDefaultLat = position.target.latitude;
mDefaultLng = position.target.longitude;
locationFromMap = true;
populate();
if (mPreviousCameraPosition[0] == null || mPreviousCameraPosition[0].zoom != position.zoom) {
mPreviousCameraPosition[0] = googleMap.getCameraPosition();
addItems();
}
}
});
mMap.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
#Override
public void onMapLoaded() {
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(location, 16));
}
});
mMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
#Override
public boolean onMarkerClick(Marker marker) {
try {
new OfficeDialog(mActivity, officeList.get(Integer.parseInt(marker.getSnippet()))).show();
} catch (Exception e) {
}
return true;
}
});
}
});
addItems function
private void addItems() {
if (!listAdded && officeList.size() > 0) {
mClusterManager.clearItems();
mClusterManager.cluster();
mClusterManager.addItems(officeList);
listAdded = true;
}
mClusterManager.cluster();
}
and my cluster manager custom render
public class ClusterRenderer extends DefaultClusterRenderer<Office> {
Context context;
private IconGenerator iconGenerator;
private float density;
public ClusterRenderer(Context context, GoogleMap map, ClusterManager<Office> clusterManager) {
super(context, map, clusterManager);
clusterManager.setRenderer(this);
this.context = context;
density = context.getResources().getDisplayMetrics().density;
}
#Override
protected void onBeforeClusterItemRendered(Office item, MarkerOptions markerOptions) {
markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.ejar_location_icon_copy));
}
#Override
protected void onBeforeClusterRendered(Cluster<Office> cluster, MarkerOptions markerOptions) {
if(iconGenerator == null) {
iconGenerator = new IconGenerator(context);
iconGenerator.setContentView(makeTextView(context));
}
iconGenerator.setBackground(makeBackground(false, cluster.getSize()));
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(iconGenerator.makeIcon(String.valueOf(cluster.getSize()))));
}
#Override
protected void onClusterRendered(Cluster<Office> cluster, Marker marker) {
super.onClusterRendered(cluster, marker);
}
#Override
protected boolean shouldRenderAsCluster(Cluster<Office> cluster) {
return cluster.getSize() > 1;
}
private ShapeDrawable makeBackground(boolean isClicked, int size) {
ShapeDrawable background = new ShapeDrawable(new OvalShape());
int color = ContextCompat.getColor(context, R.color.colorPrimary);
if (size < 50) {
color = ContextCompat.getColor(context, R.color.colorPrimary);
} else if (size < 100) {
color = ContextCompat.getColor(context, R.color.cluster_50);
} else if (size < 200) {
color = ContextCompat.getColor(context, R.color.cluster_100);
} else if (size < 1000) {
color = ContextCompat.getColor(context, R.color.cluster_200);
} else color = ContextCompat.getColor(context, R.color.cluster_1000);
background.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
return background;
}
private SquareTextView makeTextView(Context context) {
SquareTextView squareTextView = new SquareTextView(context);
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(-2, -2);
squareTextView.setLayoutParams(layoutParams);
squareTextView.setTextColor(ContextCompat.getColor(context, R.color.white));
squareTextView.setId(com.google.maps.android.R.id.text);
int twelveDpi = (int) (12.0F * density);
squareTextView.setPadding(twelveDpi, twelveDpi, twelveDpi, twelveDpi);
return squareTextView;
}
public IconGenerator getIconGenerator(boolean isClicked) {
iconGenerator.setBackground(makeBackground(isClicked, 0));
return iconGenerator;
}
}
After debug and search about this issue I didn't found any reason about it so after check my web service I found the issue on it.
Web service return static locations for my objects so the clusters not changed after fix it the application works correctly without any issues.
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 want to change my Relative layout's background every 10 seconds with fade in/fade out animation.
So I found
//Transitiondrawable
TransitionDrawable transition = (TransitionDrawable) viewObj.getBackground();
transition.startTransition(transitionTime);
But it supports only 2 Drawable and I want to add more
Is there any way to do this?
First implement MyAnim.java class as below:
public class MyAnim extends Animation {
private final RelativeLayout view;
private int targetBackGround;
public MyAnim(RelativeLayout view, int tagetBackGroundColor) {
this.view = view;
this.targetBackGround = tagetBackGroundColor;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
view.setBackgroundColor(targetBackGround);
}
public void setColor(int color) {
this.targetBackGround = color;
}
}
Then add below code to your activity and call that animateBackground() method wherever you want:
private MyAnim backgroundAnim;
private int i;
private void animateBackground(){
final RelativeLayout animLay = (RelativeLayout) findViewById(R.id.animLay);
final int colors[] = new int[]{Color.RED, Color.CYAN, Color.DKGRAY, Color.GREEN, Color.MAGENTA};
backgroundAnim = new MyAnim(animLay, colors[i]);
backgroundAnim.setDuration(1000);
animLay.startAnimation(backgroundAnim);
backgroundAnim.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
if (i == colors.length - 1) {
i = 0;
} else {
i++;
}
backgroundAnim.setColor(colors[i]);
animLay.startAnimation(backgroundAnim);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
}
You can create your own loop, something like:
int delayBetweenAnimations = 10000;
for (int i = 0; i < yourImagesArray.length ; i++) {
int delay = i * delayBetweenAnimations;
yourImageview.postDelayed(new Runnable() {
#Override
public void run() {
//set your image and animation here
}
}, delay);
}
Another way is to use recursive animation:
#Override
public void onAnimationEnd(Animator animation) {
if(check_if_you_Still_want to_loop){
//rerun your animation
}
}