android - example - google maps marker icons gallery
¿Cómo capturar ese mapa de panorámica y zoom realmente han terminado? (2)
Se encontraron horas de investigación y alguna decisión. Tiene algunos contras y pros que describiré más adelante.
Lo principal que debemos hacer es anular algunos de los métodos de MapView para manejar su comportamiento de dibujo. En caso de que no podamos anular el método draw (), deberíamos encontrar otra forma de hacerlo. Hay otra derivada de View que puede ser anulada: método computeScroll (). Se llama repetidamente a medida que el mapa continúa rellenando. Todo lo que tenemos que hacer es establecer un umbral de tiempo para atrapar si no se llama más a computeScroll esta vez.
Aquí esta lo que hice:
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);
}
}
}
A continuación, debe registrar los controladores de eventos en su MapActivity de esta manera:
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());
}
}
}
Ahora, ¿qué hay de las ventajas y desventajas de este enfoque?
Ventajas:
- Gestiones de eventos en cualquier mapa de ruta se desplazó o amplió. Evento táctil, claves de hardware utilizadas, incluso eventos activados mediante programación (como los métodos setZoom () o animate ()).
- Posibilidad de saltarse la carga innecesaria de datos si el usuario hace clic en el botón de zoom varias veces rápidamente. El evento se activará solo después de que los clics se detengan.
Desventajas:
- No es posible cancelar el zoom o la acción de panorámica (tal vez agregue esta habilidad en el futuro)
Espero que esta pequeña clase te ayude.
Intento escribir una aplicación que cargará dinámicamente datos para mapearlos mientras el usuario los mueve o los amplía.
Necesito rastrear cuándo el mapa ha terminado para cambiar su estado de visualización (deja de panoramizar o acercar) y luego cargar una nueva porción de datos para crear marcadores. Pero, de hecho, Google Maps API no tiene ningún evento para manejar esto.
Existen algunos métodos, como la creación de una superposición vacía para controlar los eventos onTouch
, etc., pero la panorámica del mapa podría durar mucho tiempo después de que el usuario haya terminado su toque porque GMaps usa algún tipo de inercia para que la bandeja sea más suave.
Traté de subclasificar a MapView
pero su método draw()
es final
por lo que no puede anularse.
¿Alguna idea de cómo hacer un manejo preciso del acabado panorámico y zoom?
El proyecto MapChange , publicado originalmente en una pregunta similar aquí , me ayudó a completar la misma tarea que pediste.