2

I am using android maps v2works fine I can add and remove markers onLong Touch on locations.

Problem: I would like to drop the marker slowly into the touched location i.e. I want the user to see the marker floating from the top of the screen to the point where it is dropped(touched location).

Currently; the marker just appears on the touched location such that you have to lift you finger to see that it has been dropped. It would be nice to see it coming from the top of the screen.

Thanks.

Androiderson
  • 16,865
  • 6
  • 62
  • 72
ngwane
  • 133
  • 1
  • 4
  • 8

4 Answers4

9

You can achieve this with a code similar to this (untested):

final LatLng target = ...;

final long duration = 400;
final Handler handler = new Handler();
final long start = SystemClock.uptimeMillis();
Projection proj = map.getProjection();

Point startPoint = proj.toScreenLocation(target);
startPoint.y = 0;
final LatLng startLatLng = proj.fromScreenLocation(startPoint);

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 * target.longitude + (1 - t) * startLatLng.longitude;
        double lat = t * target.latitude + (1 - t) * startLatLng.latitude;
        marker.setPosition(new LatLng(lat, lng));
        if (t < 1.0) {
            // Post again 10ms later.
            handler.postDelayed(this, 10);
        } else {
            // animation ended
        }
    }
});
MaciejGórski
  • 22,187
  • 7
  • 70
  • 94
  • @ngwane If you made any changes to the code to make it work, please comment and I will make the changes, so people looking for the same thing may use it directly. – MaciejGórski May 17 '13 at 17:00
  • The following imports need to be included:import android.view.animation.LinearInterpolator;import android.os.Handler; Then define markerOptions for the marker outside the run statement. The latlong part will be the changing part of the marker inside the run as you add and remove the marker repeatedly to make falling effect. Add marker to map for first time outside the run method. – ngwane May 20 '13 at 08:34
  • Inside run method first if statemnt remove the marker and add it again immediately after postdelayed statement. Add the marker remove and add staement again on the else part of teh if statemt then you will get the floating effect; you'll see the marker dropping from the top of the map moving towards the point you touched on the map. If it is moving too fats alter delay milliseconds...Thank you MaciejGórski – ngwane May 20 '13 at 08:37
5

I have combined the MaciejGórski's approach with the code from this gist. In addition, added a bounce effect.

public class MyBounceInterpolator implements android.view.animation.Interpolator {
    double mAmplitude = 1;
    double mFrequency = 10;

    public MyBounceInterpolator(double amplitude, double frequency) {
        mAmplitude = amplitude;
        mFrequency = frequency;
    }

    public float getInterpolation(float time) {
        double amplitude = mAmplitude;
        if (amplitude == 0) { amplitude = 0.05; }

        // The interpolation curve equation:
        //    -e^(-time / amplitude) * cos(frequency * time) + 1
        //
        // View the graph live: https://www.desmos.com/calculator/6gbvrm5i0s
        return (float) (-1 * Math.pow(Math.E, -time/ mAmplitude) * Math.cos(mFrequency * time) + 1);
    }
}

void dropMarker(final Marker marker, GoogleMap map) {
    final LatLng finalPosition = new LatLng(marker.getPosition().latitude, marker.getPosition().longitude);

    Projection projection = map.getProjection();
    Point startPoint = projection.toScreenLocation(finalPosition);
    startPoint.y = 0;
    final LatLng startLatLng = projection.fromScreenLocation(startPoint);
    final Interpolator interpolator = new MyBounceInterpolator(0.11, 4.6);

    TypeEvaluator<LatLng> typeEvaluator = new TypeEvaluator<LatLng>() {
        @Override
        public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) {
            float t = interpolator.getInterpolation(fraction);
            double lng = t * finalPosition.longitude + (1 - t) * startLatLng.longitude;
            double lat = t * finalPosition.latitude + (1 - t) * startLatLng.latitude;
            return new LatLng(lat, lng);
        }
    };

    Property<Marker, LatLng> property = Property.of(Marker.class, LatLng.class, "position");
    ObjectAnimator animator = ObjectAnimator.ofObject(marker, property, typeEvaluator, finalPosition);
    animator.setDuration(400);
    animator.start();
}

enter image description here

Evgenii
  • 36,389
  • 27
  • 134
  • 170
2

It works great, but it seemed to me that sometimes the marker remained one step far from the target, so I added just one more line:

if (t < 1.0) {
    // Post again 10ms later.
    handler.postDelayed(this, 50);
} else {
    // animation ended
    marker.setPosition(target);
}

Hope it helps.

gruiz
  • 33
  • 4
0

I've applied your way but have an issue that is the markers position on map is not correct. I think command below calculate is not correct. So after animation finished then final result is not same as original Lat,Lng.

double lng = t * target.longitude + (1 - t) * startLatLng.longitude; double lat = t * target.latitude + (1 - t) * startLatLng.latitude;

Tran Huu Phuoc
  • 117
  • 1
  • 6