41

有没有一种简单的方法可以使用 Android Google Maps API v2LatLngBounds从 a 获取可见地图,CameraPosition以便我可以使用它OnCameraChangeListener来获取标记的新数据。

mMap.setOnCameraChangeListener(new OnCameraChangeListener() {
            @Override
            public void onCameraChange(CameraPosition position) {
                LatLngBounds bounds = ?;
                fetchNewData(bounds);
            }
        });
4

2 回答 2

78

您无法从 CameraPosition 获取 LatLngBounds,但您可以从 GoogleMap 轻松获取它们。

private GoogleMap mMap;

mMap.setOnCameraChangeListener(new OnCameraChangeListener() {
            @Override
            public void onCameraChange(CameraPosition position) {
                LatLngBounds bounds = mMap.getProjection().getVisibleRegion().latLngBounds;
                fetchData(bounds);
            }
        });
于 2012-12-18T21:50:55.907 回答
41

自 2016 年 8 月以来的更新

总结现在这个问题的正确答案是使用新onCameraIdle的,而不是OnCameraChangeListener现在已弃用的。阅读下面的方法。

现在,您可以在最新版本的 Android 版 Google 地图上收听“dragEnd”类事件,甚至其他事件。

文档中所示,您可以通过使用新的侦听器来避免多次(又名“多次”)调用的问题。OnCameraChangeListener例如,您现在可以检查相机移动的原因是什么,这是fetchData根据要求解决问题的理想选择。以下代码大多直接取自文档。还有一件事,有必要使用Google Play Services 9.4

public class MyCameraActivity extends FragmentActivity implements
        OnCameraMoveStartedListener,
        OnCameraMoveListener,
        OnCameraMoveCanceledListener,
        OnCameraIdleListener,
        OnMapReadyCallback {

    private GoogleMap mMap;

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

        SupportMapFragment mapFragment =
            (SupportMapFragment) getSupportFragmentManager()
                    .findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);
    }

    @Override
    public void onMapReady(GoogleMap map) {
        mMap = map;

        mMap.setOnCameraIdleListener(this);
        mMap.setOnCameraMoveStartedListener(this);
        mMap.setOnCameraMoveListener(this);
        mMap.setOnCameraMoveCanceledListener(this);

        // Show Sydney on the map.
        mMap.moveCamera(CameraUpdateFactory
                .newLatLngZoom(new LatLng(-33.87365, 151.20689), 10));
    }

    @Override
    public void onCameraMoveStarted(int reason) {

        if (reason == OnCameraMoveStartedListener.REASON_GESTURE) {
            Toast.makeText(this, "The user gestured on the map.",
                           Toast.LENGTH_SHORT).show();
        } else if (reason == OnCameraMoveStartedListener
                                .REASON_API_ANIMATION) {
            Toast.makeText(this, "The user tapped something on the map.",
                           Toast.LENGTH_SHORT).show();
        } else if (reason == OnCameraMoveStartedListener
                                .REASON_DEVELOPER_ANIMATION) {
            Toast.makeText(this, "The app moved the camera.",
                           Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onCameraMove() {
        Toast.makeText(this, "The camera is moving.",
                       Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onCameraMoveCanceled() {
        Toast.makeText(this, "Camera movement canceled.",
                       Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onCameraIdle() {
        Toast.makeText(this, "The camera has stopped moving. Fetch the data from the server!", Toast.LENGTH_SHORT).show();
        LatLngBounds bounds = mMap.getProjection().getVisibleRegion().latLngBounds;
        fetchData(bounds)
    }
}

2016 年 8 月之前有效解决方案的解决方法

由于这个问题得到了正确的回答,我想补充一下可能是下一个问题的问题。

OnCameraChangeListener由于触发此方法的频率,使用从服务器获取数据时会出现问题。

有一个问题报告了在进行简单的地图滑动时触发此方法的频率有多疯狂,因此在问题的示例中fetchData,即使没有相机更改,它也会触发多个连续时间以进行非常小的相机更改,是的,它发生了相机边界没有改变,但该方法被触发。

这可能会影响服务器端的性能,并且会通过从服务器按顺序获取数据数十次而浪费大量设备资源。

您可以在该链接中找到此问题的解决方法,但还没有正式的方法来解决此问题,例如,使用期望dragEnd的 或cameraChangeEnd回调。

下面的一个例子,基于那里的例子,是我如何通过使用调用的时间间隔并丢弃具有相同边界的调用来避免上述问题。

// Keep the current camera bounds
private LatLngBounds currentCameraBounds;

new GoogleMap.OnCameraChangeListener() {
    private static int CAMERA_MOVE_REACT_THRESHOLD_MS = 500;
    private long lastCallMs = Long.MIN_VALUE;

    @Override
    public void onCameraChange(CameraPosition cameraPosition) {
      LatLngBounds bounds = map.getProjection().getVisibleRegion().latLngBounds;
      // Check whether the camera changes report the same boundaries (?!), yes, it happens
      if (currentCameraBounds.northeast.latitude == bounds.northeast.latitude
         && currentCameraBounds.northeast.longitude == bounds.northeast.longitude
         && currentCameraBounds.southwest.latitude == bounds.southwest.latitude
         && currentCameraBounds.southwest.longitude == bounds.southwest.longitude) {
         return;
       }

      final long snap = System.currentTimeMillis();
      if (lastCallMs + CAMERA_MOVE_REACT_THRESHOLD_MS > snap) {
        lastCallMs = snap;
        return;
      }

      fetchData(bounds);

      lastCallMs = snap;
      currentCameraBounds = bounds;

}
于 2015-12-02T14:40:55.653 回答