Android环绕Google地图标记的脉冲环动画

sun*_*nil 7 location google-maps mapfragment android-studio

我想在Android google mapFragment(如Uber)的蓝点当前用户位置添加脉冲环动画.

有人可以帮我这件事吗?

Deb*_*jan 14

我找到了一种将脉动动画添加到标记的解决方案.这是地图部分,这里变量"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;
    }
Run Code Online (Sandbox Code Playgroud)

您必须通过添加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;
    }
Run Code Online (Sandbox Code Playgroud)

并改变这一行

userLocation.getAccuracy()
Run Code Online (Sandbox Code Playgroud)

getDisplayPulseRadius(userLocation.getAccuracy()
Run Code Online (Sandbox Code Playgroud)

并且

.radius((Float) animation.getAnimatedValue())
Run Code Online (Sandbox Code Playgroud)

.radius(getDisplayPulseRadius((Float) animation.getAnimatedValue()))
Run Code Online (Sandbox Code Playgroud)

如果你希望颜色渐变的效果在变大时变为透明,你可以在动画制作者设置半径的下一行中使用它

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);
    }
Run Code Online (Sandbox Code Playgroud)


mit*_*501 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()
      }
}
Run Code Online (Sandbox Code Playgroud)