如何纠正Google Maps v2中标记平滑移动的问题?

6

我的应用需要在谷歌地图上显示一个平滑的“移动”标记,从一个点到另一个点。我使用以下方法进行动画处理:

public void animateMarker(final Marker marker, final LatLng toPosition,
                          final boolean hideMarker) {
    final Handler handler = new Handler();
    final long start = SystemClock.uptimeMillis();
    Projection proj = mMap.getProjection();
    Point startPoint = proj.toScreenLocation(marker.getPosition());
    final LatLng startLatLng = proj.fromScreenLocation(startPoint);
    final long duration = 500;

    final Interpolator interpolator = new LinearInterpolator();

    handler.post(new Runnable() {
        @Override
        public void run() {
            long elapsed = SystemClock.uptimeMillis() - start;
            float t = interpolator.getInterpolation((float) elapsed
                    / duration);
            double lng = t * toPosition.longitude + (1 - t)
                    * startLatLng.longitude;
            double lat = t * toPosition.latitude + (1 - t)
                    * startLatLng.latitude;
            marker.setPosition(new LatLng(lat, lng));

            if (t < 1.0) {
                // Post again 16ms later.
                handler.postDelayed(this, 16);
            } else {
                if (hideMarker) {
                    marker.setVisible(false);
                } else {
                    marker.setVisible(true);
                }
            }
        }
    });
}

但是仅仅创建一个新的标记到新位置(旧位置并未删除)会导致以下结果:

图片描述


我认为在你改变一个位置之后,在开始等待之前,你需要告诉视图重新绘制自己。 - kaho
你是不是想删除一个标记并添加一个新的标记到新位置? - Rexhaif
据我所知,为了节省资源,Android 在您的循环完成之前不会绘制屏幕...因此,您需要告诉系统您想要重新绘制屏幕。看起来这个链接会有所帮助:http://developer.android.com/reference/android/view/View.html#invalidate(android.graphics.Rect) - kaho
我尝试复制但失败了,我的正常工作:https://youtu.be/s_gZR1WHqPw - kaho
你能发一份代码吗? - Rexhaif
2个回答

25
我从官方视频中提到的项目中复制了一些代码。
我使用这段代码进行复现,似乎对我有效,所以希望我的代码能对你有所帮助,哪怕只是一点点。
static final LatLng SomePos = new LatLng(37.7796354, -122.4159606);

    try {
        if (googleMap == null) {
            googleMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
        }
        googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
        googleMap.setMyLocationEnabled(true);
        googleMap.setTrafficEnabled(false);
        googleMap.setIndoorEnabled(false);
        googleMap.setBuildingsEnabled(true);
        googleMap.getUiSettings().setZoomControlsEnabled(true);
        googleMap.moveCamera(CameraUpdateFactory.newLatLng(SomePos));
        googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder()
                .target(googleMap.getCameraPosition().target)
                .zoom(17)
                .bearing(30)
                .tilt(45)
                .build()));

        myMarker = googleMap.addMarker(new MarkerOptions()
                .position(SomePos)
                .icon(BitmapDescriptorFactory.fromResource(R.mipmap.ic_launcher))
                .title("Hello world"));


        googleMap.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener()
        {
            @Override
            public boolean onMarkerClick(Marker arg0) {

                final LatLng startPosition = myMarker.getPosition();
                final LatLng finalPosition = new LatLng(37.7801569,-122.4148528);
                final Handler handler = new Handler();
                final long start = SystemClock.uptimeMillis();
                final Interpolator interpolator = new AccelerateDecelerateInterpolator();
                final float durationInMs = 3000;
                final boolean hideMarker = false;

                handler.post(new Runnable() {
                    long elapsed;
                    float t;
                    float v;

                    @Override
                    public void run() {
                        // Calculate progress using interpolator
                        elapsed = SystemClock.uptimeMillis() - start;
                        t = elapsed / durationInMs;
                        v = interpolator.getInterpolation(t);

                        LatLng currentPosition = new LatLng(
                                startPosition.latitude*(1-t)+finalPosition.latitude*t,
                                startPosition.longitude*(1-t)+finalPosition.longitude*t);

                        myMarker.setPosition(currentPosition);

                        // Repeat till progress is complete.
                        if (t < 1) {
                            // Post again 16ms later.
                            handler.postDelayed(this, 16);
                        } else {
                            if (hideMarker) {
                                myMarker.setVisible(false);
                            } else {
                                myMarker.setVisible(true);
                            }
                        }
                    }
                });

                return true;

            }

        });

    } catch (Exception e) {
        e.printStackTrace();
    }

9

我知道这是一个老问题,但是...

您可以使用值插值器来完成此任务:

fun changePositionSmoothly(marker:Marker?, newLatLng: LatLng){
    if(marker == null){
        return;
    }
    val animation = ValueAnimator.ofFloat(0f, 100f)
    var previousStep = 0f
    val deltaLatitude = newLatLng.latitude - marker.position.latitude
    val deltaLongitude = newLatLng.longitude - marker.position.longitude
    animation.setDuration(1500)
    animation.addUpdateListener { updatedAnimation ->
        val deltaStep = updatedAnimation.getAnimatedValue() as Float - previousStep
        previousStep = updatedAnimation.getAnimatedValue() as Float
        marker.position = LatLng(marker.position.latitude + deltaLatitude * deltaStep * 1/100, marker.position.longitude + deltaStep * deltaLongitude * 1/100)
    }
    animation.start()
}

在Java中,
void changePositionSmoothly(Marker marker, LatLng newLatLng) {
        if (marker == null) {
            return;
        }
        ValueAnimator animation = ValueAnimator.ofFloat(0f, 100f);
        final float[] previousStep = {0f};
        double deltaLatitude = newLatLng.latitude - marker.getPosition().latitude;
        double deltaLongitude = newLatLng.longitude - marker.getPosition().longitude;
        animation.setDuration(1500);
        animation.addUpdateListener(animation1 -> {
            float deltaStep = (Float) animation1.getAnimatedValue() - previousStep[0];
            previousStep[0] = (Float) animation1.getAnimatedValue();
            marker.setPosition(new LatLng(marker.getPosition().latitude + deltaLatitude * deltaStep * 1 / 100, marker.getPosition().longitude + deltaStep * deltaLongitude * 1 / 100));
        });
        animation.start();
    }

为了防止误差累积,在动画结束时您可以设置新的位置,但这对大多数情况已足够。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接