在Google Map v2中动画标记的旋转

问题描述 投票:4回答:8

我正在使用Google Maps v2。我在地图上有一个标记,该标记每次都会更改旋转。我想动画制作器的旋转以使其平滑旋转。谁能帮忙

android google-maps google-maps-markers android-animation
8个回答
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());
 }

我希望有帮助。


5
投票
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 hereenter image description hereenter image description hereenter image description hereenter image description here


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

我设法做到了:)


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

}

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

1
投票

有同样的问题,我使用的是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();
}

0
投票

您想使用MarkerOption rotation method

 public MarkerOptions rotation (float rotation)

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

使用新的方法返回为其调用方法的对象 旋转集。


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()
}
© www.soinside.com 2019 - 2024. All rights reserved.