安卓中谷歌地图标记周围的脉冲环动画

9

我想在Android Google MapFragment上的蓝点当前用户位置上添加一个脉冲环动画(类似于Uber)。

有人能帮我处理这个问题吗?

2个回答

19

我已经找到了一种方法,可以为标记添加闪烁动画效果。这是地图部分,其中变量"map"表示你的地图。

private Circle lastUserCircle;
private long pulseDuration = 1000;
private ValueAnimator lastPulseAnimator;

private void addPulsatingEffect(LatLng userLatlng){
           if(lastPulseAnimator != null){
                lastPulseAnimator.cancel();
                Log.d("onLocationUpdated: ","cancelled" );
            }
            if(lastUserCircle != null)
                lastUserCircle.setCenter(userLatlng);
            lastPulseAnimator = valueAnimate(userLocation.getAccuracy(), pulseDuration, new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    if(lastUserCircle != null)
                        lastUserCircle.setRadius((Float) animation.getAnimatedValue());
                    else {
                        lastUserCircle = map.addCircle(new CircleOptions()
                                .center(userLatlng)
                                .radius((Float) animation.getAnimatedValue())
                                .strokeColor(Color.RED)
                                .fillColor(Color.BLUE));
                    }
                }
            }); 

}
protected ValueAnimator valueAnimate(float accuracy,long duration, ValueAnimator.AnimatorUpdateListener updateListener){
        Log.d( "valueAnimate: ", "called");
        ValueAnimator va = ValueAnimator.ofFloat(0,accuracy);
        va.setDuration(duration);
        va.addUpdateListener(updateListener);
        va.setRepeatCount(ValueAnimator.INFINITE);
        va.setRepeatMode(ValueAnimator.RESTART);

        va.start();
        return va;
    }

您需要在位置更新时添加PositionChangedListener来调用此方法。您可以在Google地图文档中轻松找到它。之后,对于每个更新,请调用上述方法。

将脉冲半径固定为相同的值,使其既不太大也不太小

编写此方法。

protected float getDisplayPulseRadius(float radius) {
        float diff = (map.getMaxZoomLevel() - map.getCameraPosition().zoom);
        if (diff < 3)
            return radius;
        if (diff < 3.7)
            return radius * (diff / 2);
        if (diff < 4.5)
            return (radius * diff);
        if (diff < 5.5)
            return (radius * diff) * 1.5f;
        if (diff < 7)
            return (radius * diff) * 2f;
        if (diff < 7.8)
            return (radius * diff) * 3.5f;
        if (diff < 8.5)
            return (float) (radius * diff) * 5;
        if (diff < 10)
            return (radius * diff) * 10f;
        if (diff < 12)
            return (radius * diff) * 18f;
        if (diff < 13)
            return (radius * diff) * 28f;
        if (diff < 16)
            return (radius * diff) * 40f;
        if (diff < 18)
            return (radius * diff) * 60;
        return (radius * diff) * 80;
    }

并修改这一行

userLocation.getAccuracy()

getDisplayPulseRadius(userLocation.getAccuracy()

并且也

.radius((Float) animation.getAnimatedValue())
.radius(getDisplayPulseRadius((Float) animation.getAnimatedValue()))

如果您希望在物体变大时产生一种颜色渐变到透明的效果,您可以在设置动画器内部的半径的下一行中使用以下内容:

circle.setFillColor(adjustAlpha(pulseAroundMeFillColor, 1 - animation.getAnimatedFraction()));

private int adjustAlpha(int color, float factor) {
        int alpha = Math.round(Color.alpha(color) * factor);
        int red = Color.red(color);
        int green = Color.green(color);
        int blue = Color.blue(color);
        return Color.argb(alpha, red, green, blue);
    }

帮我一下,在哪里可以找到你的"userLocation.getAccuracy()"? - kemdo
你好,我不太明白你的问题。"userLocation" 是一个 android.location.Location 对象。你可以在这里查看我的一个带有许多地图功能的项目:https://github.com/itsdebs/MapEasy,以及包含所有这些与地图相关的实现的文件:https://github.com/itsdebs/MapEasy/blob/master/app/src/main/java/com/vagabond/mapeasy/maphandler/MapManagerImpl.java。看看这是否回答了你的问题。 - Debanjan
@Debanjan:我必须放大才能看到动画。有什么办法可以设置固定大小吗?谢谢。 - user2234
@Neha 对不起晚了。这很棘手。我尝试在屏幕上找到坐标来显示脉动效果,但那从来不准确,所以我在回答中附上了唯一可能的选项。您可以使用试错方法更改它。 - Debanjan
你先生,非常棒。 - Ian Wambai

7
import android.animation.ValueAnimator
import android.graphics.Color
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.MapFragment
import com.google.android.gms.maps.model.Circle
import com.google.android.gms.maps.model.CircleOptions
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.MarkerOptions

class MainActivity : AppCompatActivity() {

     private val pulseCount = 4

     private val animationDuration = (pulseCount + 1) * 1000

     private val SAN_FRANCISCO_LOCATION = LatLng(37.7749295, -122.4194155)

     private var gMap: GoogleMap? = null

     private var circles = Array<Circle?>(pulseCount, { null })

     override fun onCreate(savedInstanceState: Bundle?) {
          super.onCreate(savedInstanceState)
          setContentView(R.layout.activity_main)

          (fragmentManager.findFragmentById(R.id.mpFrgmnt) as MapFragment).getMapAsync { map ->
               gMap = map
               setCurrentLocation()
          }
     }

     private fun setCurrentLocation() {
           gMap?.let { gMap ->
    gMap.moveCamera(CameraUpdateFactory.newLatLngZoom(SAN_FRANCISCO_LOCATION, 17f))
        gMap.animateCamera(CameraUpdateFactory.zoomIn())
        gMap.animateCamera(CameraUpdateFactory.zoomTo(17f), animationDuration, null)
        gMap.addMarker(MarkerOptions().position(SAN_FRANCISCO_LOCATION).title("San Francisco !"))

            val from = 0
            val to = 100
            val fraction = 255 / to

            for (i in 0 until pulseCount) {
                  addPulseAnimator(gMap, circles, SAN_FRANCISCO_LOCATION, from, to, fraction, i)
            }
        }
    }

     private fun addPulseAnimator(gMap: GoogleMap, circles: Array<Circle?>, latLng: LatLng, from: Int, to: Int, colorFraction: Int, currentPosition: Int) {
           val valueAnimator = ValueAnimator.ofInt(from, to)
           valueAnimator.duration = animationDuration.toLong()
           valueAnimator.repeatCount = ValueAnimator.INFINITE
           valueAnimator.repeatMode = ValueAnimator.RESTART
           valueAnimator.startDelay = currentPosition * 1000L
           valueAnimator.addUpdateListener { valueAnimator ->

        val radius = valueAnimator.animatedValue as Int

        circles[currentPosition]?.let { circle ->
            circle.center = latLng
            circle.radius = radius.toDouble()
            circle.fillColor = Color.argb((to - radius) * colorFraction, 48, 118, 254)
            circle.strokeWidth = 0f

        } ?: run {
            circles[currentPosition] = gMap.addCircle(CircleOptions()
                    .center(latLng)
                    .radius(radius.toDouble())
                    .fillColor(Color.argb((to - radius) * colorFraction, 48, 118, 254))
                    .strokeWidth(0f))
                   }
             }
             valueAnimator.start()
      }
}

代码是用Kotlin编写的,您可以直接使用Android Studio将代码转换为Java。还有一件事,它是Debanjan上面解决方案的扩展。 - mithil1501
1
非常好的回答!! - Prabhtej Singh
这对于单个标记的动画效果很好。但是当添加多个标记时,动画会有点闪烁。你尝试过在多个标记上使用吗? - nayana bhoj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接