在Google地图v2中为标记的旋转设置动画

时间:2015-03-10 15:35:41

标签: android google-maps google-maps-markers android-animation

我正在使用谷歌地图v2。 我在地图上有一个标记,这个标记每次都会改变旋转。 我想动画制作者的旋转以平滑旋转。 任何人都可以帮忙吗

8 个答案:

答案 0 :(得分:6)

我的实现平滑标记移动与制造商图像旋转(当它设置为FLAT [重要]时)。将标记平滑地移动到所请求的位置,并将其以适当的方向旋转到所需的程度。例如,当从5deg移动到355deg时,它会逆时针移动,当355deg移动到5deg时,它会顺时针移动。

public void animateMarker(final Location location)
{
    if (myMarkerLOC != null) {
        final LatLngInterpolator latLngInterpolator = new LatLngInterpolator.LinearFixed();
        ValueAnimator valueAnimator = new ValueAnimator();
        final LatLng startPosition = myMarkerLOC.getPosition();
        final float startRotation = myMarkerLOC.getRotation();
        final float angle = 180 - Math.abs(Math.abs(startRotation - location.getBearing()) - 180);
        final float right = WhichWayToTurn(startRotation, location.getBearing());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
        {
            @Override
            public void onAnimationUpdate(ValueAnimator animation)
            {
                try {
                    if (myMarkerLOC == null) // oops... destroying map during animation...
                    {
                        return;
                    }
                    float v = animation.getAnimatedFraction();
                    LatLng newPosition = latLngInterpolator.interpolate(v, startPosition, PositionUtil.toLatLng(location));
                    float rotation = startRotation + right * v * angle;
                    myMarkerLOC.setRotation((float) rotation);
                    myMarkerLOC.setPosition(newPosition);
                } catch (Exception ex) {
                    // I don't care atm..
                }
            }
        });
        valueAnimator.setFloatValues(0, 1);
        valueAnimator.setDuration(300);
        valueAnimator.start();
    }
}
private float WhichWayToTurn(float currentDirection, float targetDirection)
{
    float diff = targetDirection - currentDirection;
    if (Math.abs(diff) == 0)
    {
        return 0;
    }
    if(diff > 180)
    {
        return -1;
    }
    else
    {
        return 1;
    }
}
public interface LatLngInterpolator 
{
    public LatLng interpolate(float fraction, LatLng a, LatLng b);

    public class Linear implements LatLngInterpolator 
    {
        @Override
        public LatLng interpolate(float fraction, LatLng a, LatLng b) 
        {
            double lat = (b.latitude - a.latitude) * fraction + a.latitude;
            double lng = (b.longitude - a.longitude) * fraction + a.longitude;
            return new LatLng(lat, lng);
        }
    }
    public 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);
        }
    }
}

缺少" toLatLong"的实施方法:

 public static LatLng toLatLng(final Location location)
 {
    return new LatLng(location.getLatitude(), location.getLongitude());
 }

我希望有所帮助。

答案 1 :(得分:4)

boolean isRotating = false;
public void rotateMarker(final Marker marker, final float toRotation) {
    if(!isRotating) {
        isRotating = true;
        final Handler handler = new Handler();
        final long start = SystemClock.uptimeMillis();
        final float startRotation = marker.getRotation();
        final long duration = 1000;
        float deltaRotation = Math.abs(toRotation - startRotation) % 360;
        final float rotation = (deltaRotation > 180 ? 360 - deltaRotation : deltaRotation) *
                ((toRotation - startRotation >= 0 && toRotation - startRotation <= 180) || (toRotation - startRotation <= -180 && toRotation - startRotation >= -360) ? 1 : -1);

        final LinearInterpolator interpolator = new LinearInterpolator();
        handler.post(new Runnable() {
            @Override
            public void run() {
                long elapsed = SystemClock.uptimeMillis() - start;
                float t = interpolator.getInterpolation((float) elapsed / duration);
                marker.setRotation((startRotation + t * rotation) % 360);
                if (t < 1.0) {
                    // Post again 16ms later.
                    handler.postDelayed(this, 16);
                } else {
                    isRotating = false;
                }
            }
        });
    }
}

这是我旋转标记的方式,我不知道这是最好的代码。 但我认为它会阻止错误的轮换。编辑:添加var isRotating(感谢@TrầnVănHuy)

更新说明:
enter image description here enter image description here enter image description here enter image description here enter image description here

答案 2 :(得分:2)

static public void rotateMarker(final Marker marker, final float toRotation, GoogleMap map) {
    final Handler handler = new Handler();
    final long start = SystemClock.uptimeMillis();
    final float startRotation = marker.getRotation();
    final long duration = 1555;

    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);

            float rot = t * toRotation + (1 -t) * startRotation;

            marker.setRotation(-rot > 180 ? rot/2 : rot);
            if (t < 1.0) {
                // Post again 16ms later.
                handler.postDelayed(this, 16);
            } 
        }
    });
}

我设法做到了:)

答案 3 :(得分:1)

用@Bhagaskara Liancer回答。添加var isMarkerRotating,帮助标记顺利旋转。

private boolean isMarkerRotating = false;
public void rotateMarker(final Marker marker, final float toRotation) {
    if(!isMarkerRotating){
        final Handler handler = new Handler();
        final long start = SystemClock.uptimeMillis();
        final float startRotation = marker.getRotation();
        final long duration = 1000;
        float deltaRotation = Math.abs(toRotation - startRotation) % 360;
        final float rotation = (deltaRotation > 180 ? 360 - deltaRotation : deltaRotation) * ((toRotation - startRotation >= 0 && toRotation - startRotation <= 180)
                || (toRotation - startRotation <=-180 && toRotation- startRotation>= -360) ? 1 : -1);

        final LinearInterpolator interpolator = new LinearInterpolator();
        handler.post(new Runnable() {
            @Override
            public void run() {
                isMarkerRotating = true;
                long elapsed = SystemClock.uptimeMillis() - start;
                float t = interpolator.getInterpolation((float) elapsed / duration);
                marker.setRotation((startRotation + t* rotation)%360);
                if (t < 1.0) {
                    // Post again 16ms later.
                    handler.postDelayed(this, 16);
                }else {
                    isMarkerRotating = false;
                }
            }
        });
    }

}

答案 4 :(得分:1)

这是一个简单的例子 您可以使用以下MarkerAnimation类为旋转设置动画标记。

import android.graphics.Point;
import android.location.Location;
import android.os.Handler;
import android.os.SystemClock;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;

import com.gogrocerycart.settings.Constants;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.Projection;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;

/**
 * Created by Vinil Chandran on 7/6/18.
 */

public class MarkerAnimation {
    private static Location fromPosition;
    private static float angle = 0;
    public static void move(GoogleMap mMap, final Marker marker, final Location toPosition) {
        if (fromPosition != null && marker != null && toPosition != null) {
            final Handler handlerRotation = new Handler();
            final long startAngle = SystemClock.uptimeMillis();
            final float startRotation = marker.getRotation();
            final long durationRotation = 300;
            final Interpolator interpolatorRotation = new LinearInterpolator();
            float bearing = fromPosition.bearingTo(toPosition);
            Print.e("Bearing:" + bearing);
            angle = bearing<0?(360+bearing):bearing;
            angle = angle%360f;
            Print.e("Angle:" + angle);
            handlerRotation.post(new Runnable() {
                @Override
                public void run() {
                    long elapsed = SystemClock.uptimeMillis() - startAngle;
                    float t = interpolatorRotation.getInterpolation((float) elapsed / durationRotation);
                    float rot = t * angle + (1 - t) * startRotation;
                    float mAngle = -rot > 180 ? rot / 2 : rot;
                    marker.setRotation(mAngle);

                    if (t < 1.0) {
                        handlerRotation.postDelayed(this, 16);
                    } else {
                        final Handler handler = new Handler();
                        final long start = SystemClock.uptimeMillis();
                        Projection projection = mMap.getProjection();
                        Point startPoint = projection.toScreenLocation(marker.getPosition());
                        final LatLng startLatLng = projection.fromScreenLocation(startPoint);
                        final long duration = Constants.LOCATION_REQUEST_INTERVAL;
                        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.getLongitude() + (1 - t)
                                        * startLatLng.longitude;
                                double lat = t * toPosition.getLatitude() + (1 - t)
                                        * startLatLng.latitude;
                                marker.setPosition(new LatLng(lat, lng));
                                if (t < 1.0) {
                                    // Post again 16ms later.
                                    handler.postDelayed(this, 16);
                                }
                            }
                        });
                    }
                }
            });
        }
        fromPosition = toPosition;
    }
}

当位置发生变化时,只需调用以下代码即可移动标记。

if (carMarker != null) {
      MarkerAnimation.move(mMap,carMarker, location);
}

答案 5 :(得分:0)

您可能希望使用MarkerOption rotation method

 public MarkerOptions rotation (float rotation)
  

将标记的旋转设置为顺时针方向   标记的锚点。旋转轴垂直于   标记。旋转0对应于的默认位置   标记。当标记在地图上是平的时,默认位置为   北对齐并且旋转使得标记始终保持   平放在地图上。当标记是广告牌时,默认位置   指向并且旋转使得标记始终是   对着镜头。默认值为0.

     

使用new返回调用该方法的对象   旋转集。

答案 6 :(得分:0)

遇到同样的问题,在我的情况下,我使用了ValueAnimator

    static public void rotateMarker(final Marker marker, final float toRotation) {

    ValueAnimator animator = ValueAnimator.ofFloat(marker.getRotation(), toRotation);
    animator.setDuration(duration);
    animator.setInterpolator(new AccelerateDecelerateInterpolator());
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            float rotate = Float.parseFloat(animation.getAnimatedValue().toString());
            marker.setRotation(rotate);
        }
    });
    animator.start();
}

答案 7 :(得分:0)

Alexander Kolesnik的回答似乎是最简单的。 这是它的Kotlin扩展版本。
您可以传入一个插值器,以免发生一些抖动。

fun Marker.animateRotation(toRotation: Float, interpolator: TimeInterpolator? = AccelerateDecelerateInterpolator()) {
    val animator = ValueAnimator.ofFloat(rotation, toRotation)
    animator.duration = 500
    animator.interpolator = interpolator
    animator.addUpdateListener {
        rotation = it.animatedValue as? Float ?: return@addUpdateListener
    }

    animator.start()
}
相关问题