Search code examples
androidgoogle-maps-android-api-2google-maps-api-2

Marker Animation on Google Maps Android not working


I am trying to animate my marker instead of making it jump between the 2 points. For some reason the animation does not work.

Every time I get a new current location, I call the below code.

if (currentLatitude != 0 && currentLongitude != 0) {
            String actualRideStartTime = "";
            if (currentRideTracking.getActualRideStartTime() != 0) {
                actualRideStartTime = TIME_FORMAT.format(currentRideTracking
                        .getActualRideStartTime());
            }
            vehicleLocation = new LatLng(currentLatitude, currentLongitude);
            markerOptions = new MarkerOptions().
                    .position(vehicleLocation);    

            animateMarker(map.addMarker(markerOptions), vehicleLocation, false);
//            builder.include(vehicleLocation);
        }

AnimateMarker method

public void animateMarker(final Marker marker, final LatLng toPosition,
                              final boolean hideMarker) {
        final Handler handler = new Handler();
        final long start = SystemClock.uptimeMillis();
        Projection proj = map.getProjection();
        Point startPoint = proj.toScreenLocation(marker.getPosition());
        final LatLng startLatLng = proj.fromScreenLocation(startPoint);
        final long duration = God.DRIVER_LOCATION_UPDATE_FREQUENCY;
        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));
                Log.d(God.LOG_TAG, ">"+lat+"<"+lng) ;
                if (t < 1.0) {
                    // Post again 16ms later.
                    handler.postDelayed(this, 16);
                } else {
                    if (hideMarker) {
                        marker.setVisible(false);
                    } else {
                        marker.setVisible(true);
                        marker.showInfoWindow();
                    }
                }
            }
        });
    }

I tried commenting out // builder.include(vehicleLocation); but yet the smooth movement dont happen, instead it jumps ahead just like it used to.

Edit : Does the frequency of updates matter ? I am using googleapiclient, so I dont know how often the updates come. Maximum wait time has been set to God.DRIVER_LOCATION_UPDATE_FREQUENCY, which is used in the duration in the animateMarker method.


Solution

  • You can smooth animation for marker from start to end smth like this:

    LatLng[] line = bezier(startPosition, endPosition, 0, 0, true);
    Marker marker = mMap.addMarker(new MarkerOptions().position(startPosition));
    animateMarker(marker, 0, line);
    

    and

     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();
    }
    
    private static LatLng[] bezier(LatLng p1, LatLng p2, double arcHeight, double skew, boolean up) {
        ArrayList<LatLng> list = new ArrayList<>();
        try {
            if (p1.longitude > p2.longitude) {
                LatLng tmp = p1;
                p1 = p2;
                p2 = tmp;
            }
    
            LatLng c = new LatLng((p1.latitude + p2.latitude) / 2, (p1.longitude + p2.longitude) / 2);
    
            double cLat = c.latitude;
            double cLon = c.longitude;
    
            //add skew and arcHeight to move the midPoint
            if (Math.abs(p1.longitude - p2.longitude) < 0.0001) {
                if (up) {
                    cLon -= arcHeight;
                } else {
                    cLon += arcHeight;
                    cLat += skew;
                }
            } else {
                if (up) {
                    cLat += arcHeight;
                } else {
                    cLat -= arcHeight;
                    cLon += skew;
                }
            }
    
            list.add(p1);
            //calculating points for bezier
            double tDelta = 1.0 / 10;
            CartesianCoordinates cart1 = new CartesianCoordinates(p1);
            CartesianCoordinates cart2 = new CartesianCoordinates(p2);
            CartesianCoordinates cart3 = new CartesianCoordinates(cLat, cLon);
    
            for (double t = 0; t <= 1.0; t += tDelta) {
                double oneMinusT = (1.0 - t);
                double t2 = Math.pow(t, 2);
    
                double y = oneMinusT * oneMinusT * cart1.y + 2 * t * oneMinusT * cart3.y + t2 * cart2.y;
                double x = oneMinusT * oneMinusT * cart1.x + 2 * t * oneMinusT * cart3.x + t2 * cart2.x;
                double z = oneMinusT * oneMinusT * cart1.z + 2 * t * oneMinusT * cart3.z + t2 * cart2.z;
                LatLng control = CartesianCoordinates.toLatLng(x, y, z);
                list.add(control);
            }
    
            list.add(p2);
        } catch (Exception e) {
            Log.e(TAG, "bezier error : ", e);
        }
    
        LatLng[] result = new LatLng[list.size()];
        result = list.toArray(result);
    
        return result;
    }
    

    Please, see full example on my GitHub