Pulse animation using GroundOverlay

一世执手 提交于 2019-12-02 04:07:33

This happens because GroundOverlay is zoomed together with the google map. To avoid that you should recreate overlay for each zoom level with corrected radius for that zoom level and latitude (meters_to_pixels in example source code). For avoid GroundOverlay recreation you should store created GroundOverlay object and remove it before creating new. For that you need some changes in your showRipples() method - it should returns created overlay. Full source code for example with one marker:

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

}

So let's say you want the overlay circle radius to be a fixed dimension (relative to screen pixels) for example 1/10th of the screen width (at the current zoom).

  // 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)));

This example uses width as the scaling axis but you could just as well use height or diagonal (by using different points of the projection).

The use of 'far' can be replaced with 'near' - it is used to account for tilt so you'll have to experiment.

So now your resource value is a scaling factor and not an absolute radius value - so for this example you would set the resource value to 0.10F and use that where's it hard-coded above.

If you want the pulse (and overlay) to work after/during zoom then you'll need to update the width of the overlay circle (circle.setWidth(scaledRadius)) using the 'onCameraIdle' event - using the same computation as above for scaledRadius, such as:

public void onCameraIdle() {
    if (circle != null) {
       // compute scaled radius as in above code...

       // The 1-argument version is specifically width
       circle.setDimensions(scaledRadius);
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!