【问题标题】:How to catch that map panning and zoom are really finished?如何捕捉地图平移和缩放真的完成了?
【发布时间】:2011-04-03 19:17:30
【问题描述】:

我正在尝试编写一个应用程序,该应用程序将在用户平移或缩放地图时动态加载数据。

我需要跟踪地图何时完成以更改其视图状态(停止平移或缩放),然后加载新的数据部分以创建标记。但实际上 Google Maps API 没有任何事件来处理这个问题。

有一些方法,例如创建一个空的叠加层来控制onTouch 事件等,但地图平移可能会在用户完成触摸后持续很长时间,因为 GMaps 使用某种惯性使平移更平滑。

我试图继承MapView,但它的draw()方法是final,因此它不能被覆盖。

任何想法如何精确处理平移和缩放精加工?

【问题讨论】:

    标签: android google-maps drag dynamic-data


    【解决方案1】:

    经过数小时的研究和一些决定。它有一些缺点和优点,我将进一步描述。

    我们应该做的主要事情是重写一些 MapView 的方法来处理它的绘图行为。如果我们不能覆盖 draw() 方法,我们应该找到另一种方法。 View 的另一种衍生方法可能会被覆盖 - computeScroll() 方法。随着 map 继续填充,它被重复调用。我们所要做的就是设置一些时间阈值来捕捉这次是否不再调用 computeScroll。
    这是我所做的:

    import java.util.Timer;
    import java.util.TimerTask;
    
    import android.content.Context;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    
    import com.google.android.maps.GeoPoint;
    import com.google.android.maps.MapView;
    
    public class EnhancedMapView extends MapView {
    public interface OnZoomChangeListener {
        public void onZoomChange(MapView view, int newZoom, int oldZoom);
    }
    
    public interface OnPanChangeListener {
        public void onPanChange(MapView view, GeoPoint newCenter, GeoPoint oldCenter);
    }
    
    private EnhancedMapView _this;
    
        // Set this variable to your preferred timeout
    private long events_timeout = 500L;
    private boolean is_touched = false;
    private GeoPoint last_center_pos;
    private int last_zoom;
    private Timer zoom_event_delay_timer = new Timer();
    private Timer pan_event_delay_timer = new Timer();
    
    private EnhancedMapView.OnZoomChangeListener zoom_change_listener;
    private EnhancedMapView.OnPanChangeListener pan_change_listener;
    
    
    public EnhancedMapView(Context context, String apiKey) {
        super(context, apiKey);
        _this = this;
        last_center_pos = this.getMapCenter();
        last_zoom = this.getZoomLevel();
    }
    
    public EnhancedMapView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    
    public EnhancedMapView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
    
    public void setOnZoomChangeListener(EnhancedMapView.OnZoomChangeListener l) {
        zoom_change_listener = l;
    }
    
    public void setOnPanChangeListener(EnhancedMapView.OnPanChangeListener l) {
        pan_change_listener = l;
    }
    
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (ev.getAction() == 1) {
            is_touched = false;
        } else {
            is_touched = true;
        }
    
        return super.onTouchEvent(ev);
    }
    
    @Override
    public void computeScroll() {
        super.computeScroll();
    
        if (getZoomLevel() != last_zoom) {
                        // if computeScroll called before timer counts down we should drop it and start it over again
            zoom_event_delay_timer.cancel();
            zoom_event_delay_timer = new Timer();
            zoom_event_delay_timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    zoom_change_listener.onZoomChange(_this, getZoomLevel(), last_zoom);
                    last_zoom = getZoomLevel();
                }
            }, events_timeout);
        }
    
        // Send event only when map's center has changed and user stopped touching the screen
        if (!last_center_pos.equals(getMapCenter()) || !is_touched) {
            pan_event_delay_timer.cancel();
            pan_event_delay_timer = new Timer();
            pan_event_delay_timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    pan_change_listener.onPanChange(_this, getMapCenter(), last_center_pos);
                    last_center_pos = getMapCenter();
                }
            }, events_timeout);
        }
    }
    
    }
    

    然后你应该像这样在你的 MapActivity 中注册事件处理程序:

    public class YourMapActivity extends MapActivity {
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        mv = new EnhancedMapView(this, "<your Maps API key here>");
    
        mv.setClickable(true);
        mv.setBuiltInZoomControls(true);
    
        mv.setOnZoomChangeListener(new EnhancedMapView.OnZoomChangeListener() {
            @Override
            public void onZoomChange(MapView view, int newZoom, int oldZoom) {
                Log.d("test", "zoom changed from " + oldZoom + " to " + newZoom);
            }
        }
        mv.setOnPanChangeListener(new EnhancedMapView.OnPanChangeListener() {
            public void onPanChange(MapView view, GeoPoint newCenter, GeoPoint oldCenter) {
                Log.d("test", "center changed from " + oldCenter.getLatitudeE6() + "," + oldCenter.getLongitudeE6() + " to " + newCenter.getLatitudeE6() + "," + newCenter.getLongitudeE6());
            }
        }
    }
    

    现在这种方法的优缺点如何?
    优点:
    - 事件处理地图被平移或缩放的任何一种方式。处理触摸事件、使用的硬件键,甚至以编程方式触发的事件(如 setZoom() 或 animate() 方法)。
    - 如果用户快速单击缩放按钮几次,则能够跳过不必要的数据加载。只有在点击停止后才会触发事件。
    缺点:
    - 取消缩放或平移动作是完全不可能的(也许我以后会添加这个功能)

    希望这个小班对你有所帮助。

    【讨论】:

    • 我在使用此解决方案时注意到的另一个小问题是,更改我的 OverlayItems 之一的可绘制对象或更改旋转,computeScroll() 也会被触发,从而使 onPanChangeListener 着火。
    • 并非所有的类构造函数都初始化内部结构 _this、last_center_pos、last_zoom。据我所知,他们应该这样做。
    • (!last_center_pos.equals(getMapCenter()) || !is_touched) 应该是 (!last_center_pos.equals(getMapCenter()) && !is_touched) 否则当用户不这样做时,平移监听器会连续触发触摸屏幕。您在上面的评论中使用“and”描述了条件。
    • 我创建了一个小的 MapView 类,它包含三个事件,onClick、onPan 和 onZoom here
    【解决方案2】:

    MapChange 项目最初发布在 similar question here 上,帮助我完成了您要求的相同任务。

    【讨论】:

    • 我看到他们使用我的技术。也许他们甚至受到我上面显示的回答的启发 :) 无论如何,我很感激有人将它作为一个单独的库。
    【解决方案3】:

    现在可以使用了:

    googleMap.setOnCameraIdleListener {
                    //Do your thing
                }
    

    相机移动结束时的回调接口

    【讨论】:

      猜你喜欢
      • 2012-07-16
      • 2020-03-13
      • 2011-07-10
      • 1970-01-01
      • 2012-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多