31

マップ上を移動する車のマーカーをエミュレートするために、スムーズな遷移を実装したいと考えています。

AndroidマップAPI v2でマーカーをアニメーション化することは可能ですか?

4

4 に答える 4

32

提供されたバージョンはどれも機能しなかったため、カスタム ソリューションを実装しました。位置アニメーションと回転アニメーションの両方を提供します。

/**
 * Method to animate marker to destination location
 * @param destination destination location (must contain bearing attribute, to ensure
 *                    marker rotation will work correctly)
 * @param marker marker to be animated
 */
public static void animateMarker(Location destination, Marker marker) {
    if (marker != null) {
        LatLng startPosition = marker.getPosition();
        LatLng endPosition = new LatLng(destination.getLatitude(), destination.getLongitude());

        float startRotation = marker.getRotation();

        LatLngInterpolator latLngInterpolator = new LatLngInterpolator.LinearFixed();
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
        valueAnimator.setDuration(1000); // duration 1 second
        valueAnimator.setInterpolator(new LinearInterpolator());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override public void onAnimationUpdate(ValueAnimator animation) {
                try {
                    float v = animation.getAnimatedFraction();
                    LatLng newPosition = latLngInterpolator.interpolate(v, startPosition, endPosition);
                    marker.setPosition(newPosition);
                    marker.setRotation(computeRotation(v, startRotation, destination.getBearing()));
                } catch (Exception ex) {
                    // I don't care atm..
                }
            }
        });

        valueAnimator.start();
    }
}

アニメーションの指定された部分の回転計算。マーカーは、回転の開始から終了までにより近い方向に回転します。

private static float computeRotation(float fraction, float start, float end) {
    float normalizeEnd = end - start; // rotate start to 0
    float normalizedEndAbs = (normalizeEnd + 360) % 360;

    float direction = (normalizedEndAbs > 180) ? -1 : 1; // -1 = anticlockwise, 1 = clockwise
    float rotation;
    if (direction > 0) {
        rotation = normalizedEndAbs;
    } else {
        rotation = normalizedEndAbs - 360;
    }

    float result = fraction * rotation + start;
    return (result + 360) % 360;
} 

そして最後に Google のLatLngInterpolator:

private interface LatLngInterpolator {
    LatLng interpolate(float fraction, LatLng a, LatLng b);

    class LinearFixed implements LatLngInterpolator {
        @Override
        public LatLng interpolate(float fraction, LatLng a, LatLng b) {
            double lat = (b.latitude - a.latitude) * fraction + a.latitude;
            double lngDelta = b.longitude - a.longitude;
            // Take the shortest path across the 180th meridian.
            if (Math.abs(lngDelta) > 180) {
                lngDelta -= Math.signum(lngDelta) * 360;
            }
            double lng = lngDelta * fraction + a.longitude;
            return new LatLng(lat, lng);
        }
    }
}
于 2016-04-16T13:11:59.987 に答える
28

以下のコードを試して、Google マップ V2 のマーカーをアニメーション化してください。クラスを使用Interpolatorしてマーカーにアニメーションを適用し、以下のようにアニメーションのハンドラーで処理する必要があります。

   public void animateMarker(final Marker marker, final LatLng toPosition,
        final boolean hideMarker) {
    final Handler handler = new Handler();
    final long start = SystemClock.uptimeMillis();
    Projection proj = mGoogleMapObject.getProjection();
    Point startPoint = proj.toScreenLocation(marker.getPosition());
    final LatLng startLatLng = proj.fromScreenLocation(startPoint);
    final long duration = 500;
    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));
            if (t < 1.0) {
                // Post again 16ms later.
                handler.postDelayed(this, 16);
            } else {
                if (hideMarker) {
                    marker.setVisible(false);
                } else {
                    marker.setVisible(true);
                }
            }
        }
    });
}
于 2013-04-11T04:58:31.560 に答える