【问题标题】:Pulse animation using GroundOverlay使用 GroundOverlay 的脉冲动画
【发布时间】:2018-02-21 05:08:13
【问题描述】:

我需要通过脉冲动画显示位置 A 和位置 B。我可以使用下面的代码来实现这一点。但我面临的问题是,当缩放级别发生变化时,GroundOverlay 会改变其大小。如果位置 A 和 B 彼此靠近(即地图放大级别高),则脉冲半径太大。当我缩小时,它变得太小了。

无论地图的缩放级别如何,如何保持叠加层的大小相同。

以下代码引用自这里:Animated Transparent Circle on Google Maps v2 is NOT animating correctly

private void showRipples(LatLng latLng, int color) {
    GradientDrawable d = new GradientDrawable();
    d.setShape(GradientDrawable.OVAL);
    d.setSize(500, 500);
    d.setColor(ContextCompat.getColor(Activity.this, color));
    d.setStroke(0, Color.TRANSPARENT);

    final Bitmap bitmap = Bitmap.createBitmap(d.getIntrinsicWidth()
            , d.getIntrinsicHeight()
            , Bitmap.Config.ARGB_8888);

    // Convert the drawable to bitmap
    final Canvas canvas = new Canvas(bitmap);
    d.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
    d.draw(canvas);

    // Radius of the circle
    final int radius = getResources().getDimensionPixelSize(R.dimen.ripple_radius);

    // Add the circle to the map
    final GroundOverlay circle = googleMap.addGroundOverlay(new GroundOverlayOptions()
            .position(latLng, 2 * radius).image(BitmapDescriptorFactory.fromBitmap(bitmap)));

    // Prep the animator
    PropertyValuesHolder radiusHolder = PropertyValuesHolder.ofFloat("radius", 1, radius);
    PropertyValuesHolder transparencyHolder = PropertyValuesHolder.ofFloat("transparency", 0, 1);

    ValueAnimator valueAnimator = new ValueAnimator();
    valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
    valueAnimator.setRepeatMode(ValueAnimator.RESTART);
    valueAnimator.setValues(radiusHolder, transparencyHolder);
    valueAnimator.setDuration(DURATION);
    valueAnimator.setEvaluator(new FloatEvaluator());
    valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator valueAnimator) {
            float animatedRadius = (float) valueAnimator.getAnimatedValue("radius");
            float animatedAlpha = (float) valueAnimator.getAnimatedValue("transparency");
            circle.setDimensions(animatedRadius * 2);
            circle.setTransparency(animatedAlpha);

        }
    });

    // start the animation
    valueAnimator.start();

}

[这是我在两个位置相距很远时得到的][]1

If the two locations are close to each other I get this behaviour

如果我放大第一张图片,我会看到脉冲动画。

有没有一种方法可以使脉冲半径保持不变而不管缩放级别如何?

【问题讨论】:

  • 计算“半径”作为屏幕投影大小的函数(参见 map.getProjection())。

标签: android google-maps animation gmsgroundoverlay


【解决方案1】:

这是因为GroundOverlay 与谷歌地图一起缩放。为避免这种情况,您应该为每个缩放级别重新创建覆盖,并为该缩放级别和纬度校正半径(示例源代码中的meters_to_pixels)。为了避免GroundOverlay 重新创建,您应该存储创建的GroundOverlay 对象并在创建新对象之前将其删除。为此,您需要对 showRipples() 方法进行一些更改 - 它应该返回创建的覆盖。完整的源代码,例如一个标记:

public class MainActivity extends AppCompatActivity implements OnMapReadyCallback {

    private static final String TAG = MainActivity.class.getSimpleName();

    private final LatLng RED_MARKER = new LatLng(-37.884312, 145.000623);

    private GoogleMap mGoogleMap;
    private MapFragment mMapFragment;

    private GroundOverlay mRedPoint = null;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mMapFragment = (MapFragment) getFragmentManager()
                .findFragmentById(R.id.map_fragment);
        mMapFragment.getMapAsync(this);
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        mGoogleMap = googleMap;

        mGoogleMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
            @Override
            public void onCameraIdle() {
                // if overlay already exists - remove it
                if (mRedPoint != null) {
                    mRedPoint.remove();
                }
                mRedPoint = showRipples(RED_MARKER, Color.RED);
            }
        });
        mGoogleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(RED_MARKER, 16));
    }

    private GroundOverlay showRipples(LatLng latLng, int color) {
        GradientDrawable d = new GradientDrawable();
        d.setShape(GradientDrawable.OVAL);
        d.setSize(500, 500);
        d.setColor(color);
        d.setStroke(0, Color.TRANSPARENT);

        final Bitmap bitmap = Bitmap.createBitmap(d.getIntrinsicWidth()
                , d.getIntrinsicHeight()
                , Bitmap.Config.ARGB_8888);

        // Convert the drawable to bitmap
        final Canvas canvas = new Canvas(bitmap);
        d.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        d.draw(canvas);

        // Radius of the circle for current zoom level and latitude (because Earth is sphere at first approach)
        double meters_to_pixels = (Math.cos(mGoogleMap.getCameraPosition().target.latitude * Math.PI /180) * 2 * Math.PI * 6378137) / (256 * Math.pow(2, mGoogleMap.getCameraPosition().zoom));
        final int radius = (int)(meters_to_pixels * getResources().getDimensionPixelSize(R.dimen.ripple_radius));

        // Add the circle to the map
        final GroundOverlay circle = mGoogleMap.addGroundOverlay(new GroundOverlayOptions()
                .position(latLng, 2 * radius).image(BitmapDescriptorFactory.fromBitmap(bitmap)));

        // Prep the animator
        PropertyValuesHolder radiusHolder = PropertyValuesHolder.ofFloat("radius", 1, radius);
        PropertyValuesHolder transparencyHolder = PropertyValuesHolder.ofFloat("transparency", 0, 1);

        ValueAnimator valueAnimator = new ValueAnimator();
        valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
        valueAnimator.setRepeatMode(ValueAnimator.RESTART);
        valueAnimator.setValues(radiusHolder, transparencyHolder);
        valueAnimator.setDuration(1000);
        valueAnimator.setEvaluator(new FloatEvaluator());
        valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                float animatedRadius = (float) valueAnimator.getAnimatedValue("radius");
                float animatedAlpha = (float) valueAnimator.getAnimatedValue("transparency");
                circle.setDimensions(animatedRadius * 2);
                circle.setTransparency(animatedAlpha);

            }
        });

        // start the animation
        valueAnimator.start();

        return circle;
    }

}

【讨论】:

    【解决方案2】:

    假设您希望覆盖圆半径为固定尺寸(相对于 屏幕像素)例如屏幕宽度的 1/10(当前缩放时)。

      // compute width of visible region
    
      // get lat-lng of left and right points
      LatLng left = googleMap.getProjection().getVisibleRegion().farLeft;
      LatLng right = googleMap.getProjection().getVisibleRegion().farRight;
    
    
      // compute distance between points
      float[] results = new float[1];
      Location.distanceBetween(left.latitude, left.longitude,right.latitude,right.longitude, results);
    
      // scale to desired relative radius size
      float scaledRadius = results[0] * 0.10F;
    
      // and use that for radius - taken from OP code and use 'scaledRadius'
      final GroundOverlay circle = googleMap.addGroundOverlay(new GroundOverlayOptions()
                  .position(latLng, scaledRadius).image(BitmapDescriptorFactory.fromBitmap(bitmap)));
    

    此示例使用宽度作为缩放轴,但您也可以使用高度或对角线(通过使用投影的不同点)。

    “远”的使用可以替换为“近” - 它用于说明倾斜,因此您必须进行试验。

    所以现在您的资源值是一个缩放因子,而不是绝对半径值 - 因此对于本示例,您可以将资源值设置为 0.10F 并使用上面硬编码的位置。

    如果您希望脉冲(和叠加)在缩放之后/期间起作用,那么您需要使用“onCameraIdle”事件更新叠加圆的宽度 (circle.setWidth(scaledRadius)) - 使用相同的计算同上 scaledRadius,如:

    public void onCameraIdle() {
        if (circle != null) {
           // compute scaled radius as in above code...
    
           // The 1-argument version is specifically width
           circle.setDimensions(scaledRadius);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-10-18
      • 1970-01-01
      • 2015-02-02
      • 1970-01-01
      • 2015-09-02
      • 2021-12-03
      • 2021-08-30
      • 2021-08-09
      • 1970-01-01
      相关资源
      最近更新 更多