2012-12-18 82 views
34

是否有一种简单的方法可以通过Android Google Maps API v2从CameraPosition获取可见地图的LatLngBounds,以便我可以使用OnCameraChangeListener获取标记的新数据。Google Maps API v2:来自CameraPosition的LatLngBounds

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

回答

27

更新自2016年八月

摘要正确现在答案这个问题是使用新onCameraIdle,而不是OnCameraChangeListener,这是现在deprecated。读下面的话。

现在,您可以收听“dragEnd”式的活动,甚至可以收听最新版Android版Google地图上的其他活动。

正如docs所示,您可避免多次的问题(又名“几个”)的OnCameraChangeListener通过使用新的听众来电。例如,您现在可以查看相机移动背后的原因,这是根据要求加上fetchData问题的理想选择。以下代码大部分直接来自文档。还有一件事,有必要使用Google Play Services 9.4。 2016年8月

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

解决方法了有效的解决方案之前,由于问题的正确回答,我想上添加一个可能是下一个问题。

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

有报道关于如何疯狂地频繁出现问题的例子做一个简单的地图时滑动,因而这种方法被触发的issue,它会引发fetchData多个连续的时间非常的小相机的变化,即使没有摄像头的变化,是的,碰巧相机边界没有改变,但方法被触发。

这可以在服务器端性能的影响,并会被从服务器获取数据连续数十倍浪费了大量的设备的资源。

您可以在该链接中找到此问题的解决方法,但尚未有官方的方式来执行此操作,例如,使用期望的dragEndcameraChangeEnd回调。

一个例子波纹管的基础上,从那里的人,是我如何通过与呼叫的时间间隔玩,放弃与同一边界的调用避免上述问题。

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

} 
+0

非常好! 这可能为我节省了几个小时的工作理解,然后解决这个问题。 谢谢! – EZDsIt

+0

@EZDsIt欢迎您! – Eduardo

+0

你还应该检查'null'字段'currentCameraBounds'。 –

74

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

private GoogleMap mMap; 

mMap.setOnCameraChangeListener(new OnCameraChangeListener() { 
      @Override 
      public void onCameraChange(CameraPosition position) { 
       LatLngBounds bounds = mMap.getProjection().getVisibleRegion().latLngBounds; 
       fetchData(bounds); 
      } 
     }); 
+0

我想知道他们为什么这样设置它。可见区域不应该与地图投影有任何关系。 – capdragon

+4

@capdragon等等,什么?地图投影恰好定义了定义可见区域的4个坐标 – h4lc0n

+1

我想我说的是他们不应该像那样耦合。不管投影是EPSG:4326还是EPSG:900913,无论投影是经纬度坐标还是米x/y,视图都是相同的。所以应该可以独立执行'mMap.getProjection()'或'mMap.getVisibleRegion()'。 – capdragon