我需要检测MapView的滚动或缩放时间,例如javascript API中的“moveend”事件。我想等到视图停止移动,然后我可以检测是否需要向服务器查询带有查看矩形的项目,如果是,则发出请求。 (实际上我发送了一个比观察矩形略大的区域的请求)
显然,如果视图仍在移动,我宁愿不发送数据请求。但更糟糕的是,我不知道我需要发送另一个请求,使地图区域缺少标记。
目前我正在继承MapView并按如下方式处理onTouchEvent:
public boolean onTouchEvent(android.view.MotionEvent ev) {
super.onTouchEvent (ev);
if (ev.getAction() == MotionEvent.ACTION_UP) {
GeoPoint center = getMapCenter();
int latSpan = getLatitudeSpan(), lngSpan = getLongitudeSpan();
/* (check if it has moved enough to need a new set of data) */
}
return true;
}
问题是,我不知道视图是否已经停止,因为滚动趋于惯性并且可以继续经过“ACTION_UP”事件。
是否有一些我可以使用的事件会在mapview完成移动(或缩放)时提醒我?如果没有,有没有人写过逻辑来检测这个?从理论上讲,我可以通过查看所有动作进行猜测,并稍后设置一些东西并检查它......但是......这看起来很麻烦而且是PITA。但如果有人已经写了......:)
答案 0 :(得分:13)
这是我目前正在使用的方法,我已经使用过它并对其进行了测试,效果很好。
只需确保您的draw()
方法有效。 (避免使用GC)。
//In map activity
class MyMapActivity extends MapActivity {
protected void onCreate(Bundle savedState){
setContent(R.layout.activity_map);
super.onCreate(savedSate);
OnMapMoveListener mapListener = new OnMapMoveListener(){
public void mapMovingFinishedEvent(){
Log.d("MapActivity", "Hey look! I stopped scrolling!");
}
}
// Create overlay
OnMoveOverlay mOnMoveOverlay = new OnMoveOverlay(mapListener);
// Add overlay to view.
MapView mapView = (MapView)findViewById(R.id.map_view);
// Make sure you add as the last overlay so its on the top.
// Otherwise other overlays could steal the touchEvent;
mapView.getOverlays().add(mOnMoveOverlay);
}
}
这是您的OnMoveOverlay类
//OnMoveOverlay
class OnMoveOverlay extends Overlay
{
private static GeoPoint lastLatLon = new GeoPoint(0, 0);
private static GeoPoint currLatLon;
// Event listener to listen for map finished moving events
private OnMapMoveListener eventListener = null;
protected boolean isMapMoving = false;
public OnMoveOverlay(OnMapMoveListener eventLis){
//Set event listener
eventListener = eventLis;
}
@Override
public boolean onTouchEvent(android.view.MotionEvent ev)
{
super.onTouchEvent(ev);
if (ev.getAction() == MotionEvent.ACTION_UP)
{
// Added to example to make more complete
isMapMoving = true;
}
//Fix: changed to false as it would handle the touch event and not pass back.
return false;
}
@Override
public void draw(Canvas canvas, MapView mapView, boolean shadow)
{
if (!shadow)
{
if (isMapMoving)
{
currLatLon = mapView.getProjection().fromPixels(0, 0);
if (currLatLon.equals(lastLatLon))
{
isMapMoving = false;
eventListener.mapMovingFinishedEvent();
}
else
{
lastLatLon = currLatLon;
}
}
}
}
public interface OnMapMoveListener{
public void mapMovingFinishedEvent();
}
}
只需实现你自己的监听器eventListener.mapMovingFinishedEvent();
,然后通过上面的其他方法和你的排序来激活地图移动bool。
这个想法是当地图将像素投影移动到坐标时会发生变化,一旦它们相同,你就完成了移动。
我用更新更完整的代码更新了这个,它有双重绘图的问题。
我们不会对阴影传递做任何事情,因为我们只会对每次抽签通过双重计算,这是一种浪费。
随意提出任何问题:)
谢谢, 克里斯
答案 1 :(得分:8)
我有同样的问题并以类似的方式“解决”它,但我觉得不那么复杂: 由于重写computeScroll()对我不起作用,我也过度使用了onTouchEvent。然后我使用了一个Handler,它在50ms后调用一个方法调用,如果地图中心改变了,同样会再次发生,如果地图中心没有改变,则调用监听器。我在onTouchEvent中调用的方法如下所示:
private void refreshMapPosition() {
GeoPoint currentMapCenter = getMapCenter();
if (oldMapCenter==null || !oldMapCenter.equals(currentMapCenter)) {
oldMapCenter = currentMapCenter;
handler.postDelayed(new Runnable() {
@Override
public void run() {
refreshMapPosition();
}
}, 50);
}
else {
if (onScrollEndListener!=null)
onScrollEndListener.onScrollEnd(currentMapCenter);
}
}
但我也在等待一个真正的解决方案......
答案 2 :(得分:2)
我对这个问题没有一个满意的解决方案,但我可以告诉我做了什么来部分解决它。
MapView
子类化并覆盖computeScroll()
方法,该方法获取地图的当前中心点并将其与最后已知的中心点(存储为volatile
进行比较子类中的字段)。如果中心点已更改,它会向地图的侦听器触发一个事件(我为此定义了一个自定义侦听器接口)。AsyncTask
的子类并执行它的活动。在执行服务器数据提取之前,此任务在其doInBackGround()
方法中暂停100毫秒。AsyncTask
的状态。如果该任务仍在运行,它将cancel()
。然后它创建一个新任务,然后执行该任务。总体效果是,当侦听器在几毫秒之间获得一系列映射移动事件时,实际触发任务执行服务器获取的唯一一个是序列中的最后一个。缺点是它在地图移动发生和服务器提取之间引入了一点延迟。
我对它不满意,它很难看,但它减轻了这个问题。我会爱看到更好的解决方案。
答案 3 :(得分:2)
我用一个线程解决了它,它似乎工作得很好。它不仅可以检测中心变化,还可以缩放变化。好吧,检测是在缩放和滚动结束后完成的。如果您需要在向上移动第一根手指时检测缩放更改,则可以稍微修改我的代码以检测不同的指针。但我不需要它,所以不包括它并为你留下一些功课:D
public class CustomMapView extends MapView {
private GeoPoint pressGP;
private GeoPoint lastGP;
private int pressZoom;
private int lastZoom;
public boolean onTouchEvent( MotionEvent event ) {
switch( event.getAction() ) {
case MotionEvent.ACTION_DOWN:
pressGP = getMapCenter();
pressZoom = getZoomLevel();
break;
case MotionEvent.ACTION_UP:
lastGP = getMapCenter();
pressZoom = getZoomLevel();
if( !pressGP.equals( lastGP ) ) {
Thread thread = new Thread() {
public void run() {
while( true ) {
try {
Thread.sleep( 100 );
} catch (InterruptedException e) {}
GeoPoint gp = getMapCenter();
int zl = getZoomLevel();
if( gp.equals( lastGP ) && zl == lastZoom)
break;
lastGP = gp;
lastZoom = zl;
}
onMapStop( lastGP );
}
};
thread.start();
}
break;
}
return super.onTouchEvent( event );
}
public void onMapStop( GeoPoint point , int zoom ){
// PUT YOUR CODE HERE
}
}
答案 4 :(得分:1)
使用最新版本的谷歌地图API(V2),有一个听众可以做到这一点,即GoogleMap.OnCameraChangeListener
。
mGoogleMap.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener()
{
@Override
public void onCameraChange(CameraPosition cameraPosition)
{
Toast.makeText(mActivity, "Longitude : "+cameraPosition.target.longitude
+", Latitude : "+cameraPosition.target.latitude, Toast.LENGTH_SHORT).show();
}
});