繁体   English   中英

在谷歌地图 v2 中动画标记的旋转

[英]Animate the rotation of the Marker in google map v2

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

这是我通过制造商图像旋转实现的平滑标记移动(当它设置为 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());
 }

我希望这有帮助。

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ần Văn Huy)

更新说明:
在此处输入图片说明 在此处输入图片说明 在此处输入图片说明 在此处输入图片说明 在此处输入图片说明

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

我设法做到了:)

使用@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;
                }
            }
        });
    }

}

这是一个简单的示例您可以使用以下 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);
}

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

您想使用MarkerOption 旋转方法

 public MarkerOptions rotation (float rotation)

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

返回调用该方法的对象,并设置新的旋转。

来自 Alexandr 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()
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM