【问题标题】:Pulse ring animation around a Google Maps marker in AndroidAndroid 中围绕 Google 地图标记的脉冲环动画
【发布时间】:2017-05-31 02:11:17
【问题描述】:

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

有人可以帮我解决这个问题吗?

【问题讨论】:

    标签: google-maps android-studio location mapfragment


    【解决方案1】:

    我找到了一种将脉动动画添加到标记的解决方案。 这是地图部分,这里变量“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()”在哪里
    • 您好,我不明白您的问题。 “userLocation”是一个 android.location.Location 对象。你可以在这里查看我的一个具有许多地图功能的项目。 github.com/itsdebs/MapEasy 和所有这些与地图相关的实现的文件在这里。 github.com/itsdebs/MapEasy/blob/master/app/src/main/java/com/… 看看,如果这回答了您的问题。
    • @Debanjan:我必须放大才能看到动画。知道如何设置固定大小吗?谢谢
    • @Neha 抱歉迟到了。那很难。我尝试找出屏幕中的坐标,以显示脉动效果,但这从来都不是准确的,所以我在答案中附上了唯一可能的选项。您可以使用试错法来改变这一点。
    • 你先生,真是太棒了。
    【解决方案2】:
    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 上述解决方案的扩展。
    • 很好的答案!
    • 这适用于单标记动画。但是当为多个标记添加时,动画会闪烁。您是否尝试过多个标记?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-26
    • 1970-01-01
    • 2015-11-12
    • 2015-12-05
    • 1970-01-01
    相关资源
    最近更新 更多