Des heures de recherche et une décision ont été trouvées. Il a quelques inconvénients et avantages que je décrirai plus loin.
La principale chose que nous devrions faire est de remplacer certaines méthodes de MapView pour gérer son comportement de dessin. Dans le cas où nous ne pouvons pas surcharger la méthode draw(), nous devrions trouver une autre méthode. Il existe une autre dérivée de View qui peut être surchargée - la méthode computeScroll(). Il est appelé à plusieurs reprises alors que la carte continue de remplir. Tout ce que nous avons à faire est de définir un seuil de temps à attraper si computeScroll n'est plus appelé cette fois.
Voici ce que je faisais:
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);
}
}
}
Ensuite, vous devez vous inscrire gestionnaires d'événements dans votre MapActivity comme ceci:
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());
}
}
}
Maintenant que sur les avantages et les inconvénients de cette approche?
Avantages:
- Les poignées d'événements dans l'une ou l'autre des directions ont été panoramisées ou agrandies. L'événement tactile, les clés matérielles utilisées, même les événements déclenchés par programmation sont gérés (comme les méthodes setZoom() ou animate()).
- Possibilité d'ignorer le chargement inutile de données si l'utilisateur clique plusieurs fois sur le bouton de zoom rapidement. L'événement se déclenchera seulement après que les clics s'arrêteront.
Inconvénients:
- Il est tout à fait impossible d'annuler le zoom ou une action panoramique (peut-être je vais ajouter cette capacité à l'avenir)
espère que cette petite classe vous aidera.
Un autre petit problème que j'ai remarqué lors de l'utilisation de cette solution, est que le fait de changer le drawable pour un de mes 'OverlayItem's ou de changer la rotation, computeScroll() serait également déclenché, provoquant le' onPanChangeListener'. – rogerkk
Tous les constructeurs de classe n'initialisent pas les internes _this, last_center_pos, last_zoom. Autant que je sache, ils devraient. – Theo
(! Last_center_pos.equals (getMapCenter()) ||! Is_touched) doit être (! Last_center_pos.equals (getMapCenter()) &&! Is_touched) sinon l'écouteur pan se déclenche en continu lorsque l'utilisateur ne touche pas l'écran. Vous l'aviez bien dans le commentaire au-dessus de cette ligne où vous avez décrit les conditions en utilisant 'et'. – Theo