使用GroundOverlay进行脉冲动画 [英] Pulse animation using GroundOverlay

查看:99
本文介绍了使用GroundOverlay进行脉冲动画的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



无论地图的缩放级别如何,都应保持叠加层的大小不变。



下面的代码是从这里引用的:





对于第一个图像,如果我放大,则可以看到脉冲动画。



有没有一种方法可以保持不论缩放级别如何,脉冲半径都相同?

解决方案

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

 公共类MainActivity扩展了AppCompatActivity实现的OnMapReadyCallback {

private静态最终字符串TAG = MainActivity.class.getSimpleName();

私人最终LatLng RED_MARKER =新LatLng(-37.884312,145.000623);

私人GoogleMap mGoogleMap;
私人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(mRedPoint!= null){
mRedPoint.remove();
}
mRedPoint = showRipples(RED_MARKER,Color.RED);
}
} );
mGoogleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(RED_MARKER,16));
}

私人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);

最终位图位图= Bitmap.createBitmap(d.getIntrinsicWidth()
,d.getIntrinsicHeight()
,Bitmap.Config.ARGB_8888);

//将可绘制对象转换为位图
final Canvas canvas = new Canvas(bitmap);
d.setBounds(0,0,canvas.getWidth(),canvas.getHeight());
d.draw(画布);

//当前缩放水平和纬度的圆弧半径(因为地球是第一种方法的球面)
double meter_to_pixels =(Math.cos(mGoogleMap.getCameraPosition()。target.latitude * Math.PI / 180)* 2 * Math.PI * 6378137)/(256 * Math.pow(2,mGoogleMap.getCameraPosition()。zoom));
最终int半径=(int)(meters_to_pixels * getResources()。getDimensionPixelSize(R.dimen.ripple_radius));

//将圆圈添加到地图中
最后的GroundOverlay圆圈= mGoogleMap.addGroundOverlay(new GroundOverlayOptions()
.position(latLng,2 * radius).image(BitmapDescriptorFactory。 fromBitmap(bitmap)));

//准备动画器
PropertyValuesHolder radiusHolder = PropertyValuesHolder.ofFloat( radius,1,radius);
PropertyValuesHolder transparentHolder = PropertyValuesHolder.ofFloat( transparency,0,1);

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

}
});

//开始动画
valueAnimator.start();

返回圈子;
}

}


I need to show location A and the location B by pulse animation. I am able to achieve that using the below code. But the problem I am facing is the GroundOverlay changes its size when the zoom level changes. If the location A and B are close to each other(i.e the map zoom in level is high) the radius of the pulse is too big. When I zoom out then it becomes too small.

How can I keep the size of the overlay same irrespective of the zoom level of the map.

The below code is referred from here: 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();

}

[this is what I get when the two locations are far from each other][]1

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

For the first image if I zoom in, then I do see the pulse animation.

Is there a way I can keep the radius of the pulse same irrespective of the zoom level ?

解决方案

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

}

这篇关于使用GroundOverlay进行脉冲动画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆