【问题标题】:Animate the rotation of the Marker in google map v2在谷歌地图 v2 中为标记的旋转设置动画
【发布时间】:2015-05-12 03:11:35
【问题描述】:

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

【问题讨论】:

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


    【解决方案1】:

    这是我实现的平滑标记移动与制造商图像旋转(当它设置为 FLAT [重要] 时)。标记平滑地移动到请求的位置,并以正确的方向旋转到请求的角度。例如,从 5 度到 355 度时,它逆时针移动,当 355 度到 5 度时,它顺时针移动。

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

    我希望这会有所帮助。

    【讨论】:

    • 什么是 PositionUtil?
    • 我认为 PositionUtil 是一个自定义类,它具有将 Location 对象转换为 LatLng 对象的方法。如果我错了,请纠正我。这只是绘制多个标记而不是动画标记。你能解释一下为什么会这样吗?
    • @The_Martian:PositionUtil 是我用于各种计算的实用程序类。在这种情况下,“PositionUtil.toLatLng”是将位置转换为 LatLong 的静态方法。所以是的,你是对的:)
    • 我无法让我的标记随方向旋转
    • 什么意思?如果位置包含正确的方位角,它只会向那个方向旋转。
    【解决方案2】:
    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)

    更新说明:

    【讨论】:

    • 我在找那个角度计算!
    • @ChintanShah 看起来这个角度计算为rotation 提供了错误的值(符号)。例如 -41 代替 41 或 54.5 代替 -54.5。你修好了吗?
    • 重要提示 toRotation应该在-180到180之间。例如可以使用(float)SphericalUtil.computeHeading(startPosition, endPosition)这个方法返回值范围内[-180,180) googlemaps.github.io/android-maps-utils/javadoc/com/google/maps/…
    • @ViT-Vetal- 我没有检查您提供的值,但一年前在我的项目中实施时它对我来说工作正常。
    • @ViT-Vetalsry 兄弟,我假设您误解了我的“标志”,我已经更新了我的答案并提供了详细解释。谢谢
    【解决方案3】:
    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);
                } 
            }
        });
    }
    

    我已经做到了:)

    【讨论】:

    • 你是如何计算 toRotation 的?
    • 在北半球左右两侧移动时实际上效果不佳 - 例如:350deg -> 10deg - 它不是顺时针移动而是逆时针移动或相反的 10deg -> 350deg - 它是不是逆时针移动而是顺时针移动,这是错误的。它应该采取更短的转弯。
    • 请说明如何到达Rotation
    • @user007 你修好了吗?
    【解决方案4】:

    使用@Bhagaskara Liancer answer.Add 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;
                    }
                }
            });
        }
    
    }
    

    【讨论】:

      【解决方案5】:

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

      【讨论】:

        【解决方案6】:

        遇到同样的问题,在我的情况下,我使用了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】:

          你会想使用MarkerOption rotation method

           public MarkerOptions rotation (float rotation)
          

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

          返回调用方法的对象,新的 旋转集。

          【讨论】:

            【解决方案8】:

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

            【讨论】:

              猜你喜欢
              • 2016-09-29
              • 2012-12-07
              • 1970-01-01
              • 1970-01-01
              • 2013-06-18
              • 1970-01-01
              • 2014-01-02
              • 1970-01-01
              • 2012-05-20
              相关资源
              最近更新 更多