小时的研究和一些决定被发现。它有一些我将进一步描述的缺点和优点。
我们应该做的主要事情是重写一些MapView的方法来处理其绘图行为。如果我们不能重写draw()方法,我们应该找到另一种方法。还有一种可能被重写的派生参数 - computeScroll()方法。它会在地图继续填充时重复调用。我们所要做的就是设置一些时间阈值来捕获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()方法)。
- 如果用户快速点击几次缩放按钮,可跳过不必要的数据加载。事件只会在点击停止后才会触发。
缺点:
- 这是很不可能取消缩放或平移动作(也许我会添加在将来这种能力)
希望这个小类会帮助你。
使用此解决方案时我注意到的另一个小问题是,更改我的一个'OverlayItem'的drawable或更改旋转时,computeScroll()也会触发,从而导致'onPanChangeListener'触发。 – rogerkk 2011-04-17 08:15:10
并非所有的类构造函数都会初始化内部_this,last_center_pos,last_zoom。据我所知,他们应该。 – Theo 2011-08-05 17:27:12
(!last_center_pos.equals(getMapCenter())||!is_touched)应该是(!last_center_pos.equals(getMapCenter())&&!is_touched)否则,当用户不触摸屏幕时,pan侦听器会持续触发。您在上面的注释中说明了您使用'和'描述了条件。 – Theo 2011-08-05 17:57:28