知道地图何时停止滚动(如javascript API中的"moveend")

rob*_*rob 11 android google-maps

我需要检测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;
    }
Run Code Online (Sandbox Code Playgroud)

问题是,我不知道视图是否已经停止,因为滚动往往具有惯性并且可以继续经过"ACTION_UP"事件.

是否有一些我可以使用的事件会在mapview完成移动(或缩放)时提醒我?如果没有,有没有人写过逻辑来检测这个?从理论上讲,我可以通过查看所有动作进行猜测,并稍后设置一些东西并检查它......但是......这看起来很麻烦而且是PITA.但如果有人已经写了...... :)

Chr*_*ins 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);
  }

}
Run Code Online (Sandbox Code Playgroud)

这是您的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();
            }
}
Run Code Online (Sandbox Code Playgroud)

只需实现你自己的监听器eventListener.mapMovingFinishedEvent();并通过上面的另一种方法和你的排序来激活地图移动bool.

这个想法是当地图将像素投影移动到坐标时会发生变化,一旦它们相同,你就完成了移动.

我用更新的更完整的代码更新了这个,它有一个问题,它是双重绘图.

我们在阴影传球上没有做任何事情,因为我们只会对每次抽牌传球加倍计算,这是一种浪费.

随意问任何问题 :)

谢谢,克里斯

  • 目前正在开发一个新的库,为地图添加一些非常有用的工具,这已经添加到了 - wip:https://github.com/chrisjenx/AndroidMapLibrary (2认同)

小智 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

但我也在等待一个真正的解决方案......


ska*_*man 2

对于这个问题,我确实没有令人满意的解决方案,但我可以告诉我我做了什么来部分解决它。

  • 我对该方法进行了子类化MapView和覆盖computeScroll(),该方法获取地图的当前中心点并将其与最后一个已知的中心点(存储为volatile子类中的字段)进行比较。如果中心点发生变化,它会向地图的侦听器触发一个事件(我为此定义了一个自定义侦听器接口)。
  • 侦听器是实例化子类AsyncTask并执行它的活动。doInBackGround()在执行服务器数据获取之前,此任务在其方法中暂停 100 毫秒。
  • 当侦听器活动接收到第二个地图移动事件时(由于地图移动的步进效应,它会执行此事件),它会检查刚刚执行的AsyncTask. 如果该任务仍在运行,它就会cancel()运行。然后它创建一个新任务并执行它。

总体效果是,当侦听器收到一系列相隔几毫秒的地图移动事件时,唯一真正触发任务以执行服务器获取的事件是序列中的最后一个事件。缺点是它在地图移动发生和服务器获取发生之间引入了轻微的延迟。

我对此不满意,它很丑,但它缓解了问题。我很想看到更好的解决方案。