Google Maps Android API v2 – detectar el toque en el mapa

No puedo encontrar un ejemplo de cómo interceptar el toque de mapa en la nueva API de Google Maps v2.

Necesito saber cuando el usuario toca el mapa para detener un hilo (el centrado del mapa alrededor de mi ubicación actual).

@ape escribió una respuesta aquí sobre cómo interceptar los clics del mapa, pero tengo que interceptar los toques, y luego sugirió el siguiente enlace en un comentario de su respuesta, ¿Cómo manejar evento onTouch para el mapa en Google Map API v2? .

Esa solución parece ser una posible solución, pero el código sugerido era incompleto. Por esta razón lo volví a escribir y probé, y ahora funciona.

Aquí está el código de trabajo:

Creé la clase MySupportMapFragment.java

 import com.google.android.gms.maps.SupportMapFragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; public class MySupportMapFragment extends SupportMapFragment { public View mOriginalContentView; public TouchableWrapper mTouchView; @Override public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) { mOriginalContentView = super.onCreateView(inflater, parent, savedInstanceState); mTouchView = new TouchableWrapper(getActivity()); mTouchView.addView(mOriginalContentView); return mTouchView; } @Override public View getView() { return mOriginalContentView; } } 

Incluso creé la clase TouchableWrapper.java:

 import android.content.Context; import android.view.MotionEvent; import android.widget.FrameLayout; public class TouchableWrapper extends FrameLayout { public TouchableWrapper(Context context) { super(context); } @Override public boolean dispatchTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: MainActivity.mMapIsTouched = true; break; case MotionEvent.ACTION_UP: MainActivity.mMapIsTouched = false; break; } return super.dispatchTouchEvent(event); } } 

En el diseño lo declaro de esta manera:

 <fragment xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/mapFragment" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_below="@+id/buttonBar" class="com.myFactory.myApp.MySupportMapFragment" /> 

Apenas para la prueba en la actividad principal escribí solamente el siguiente:

 public class MainActivity extends FragmentActivity { public static boolean mMapIsTouched = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } } 

Aquí está una solución simple para conseguir la localización basada en la selección del usuario (opción del tecleo en mapa)

  googleMap.setOnMapClickListener(new OnMapClickListener() { @Override public void onMapClick(LatLng arg0) { // TODO Auto-generated method stub Log.d("arg0", arg0.latitude + "-" + arg0.longitude); } }); 

Esta función y muchos más son compatibles ahora 🙂

Esta es la nota del desarrollador (Número 4636):

El lanzamiento de agosto de 2016 introduce un conjunto de nuevos oyentes de cambio de cámara para el inicio de movimiento de cámara, en curso y eventos finales. También puede ver por qué la cámara se mueve, ya sea causada por gestos de usuario, animaciones API incorporadas o movimientos controlados por desarrolladores. Para obtener más información, consulte la guía de eventos de cambio de cámara: https://developers.google.com/maps/documentation/android-api/events#camera-change-events

Consulte también las notas de la versión: https://developers.google.com/maps/documentation/android-api/releases#august_1_2016.

Aquí hay un fragmento de código de la página de documentación

 public class MyCameraActivity extends FragmentActivity implements OnCameraMoveStartedListener, OnCameraMoveListener, OnCameraMoveCanceledListener, OnCameraIdleListener, OnMapReadyCallback { private GoogleMap mMap; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my_camera); SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager() .findFragmentById(R.id.map); mapFragment.getMapAsync(this); } @Override public void onMapReady(GoogleMap map) { mMap = map; mMap.setOnCameraIdleListener(this); mMap.setOnCameraMoveStartedListener(this); mMap.setOnCameraMoveListener(this); mMap.setOnCameraMoveCanceledListener(this); // Show Sydney on the map. mMap.moveCamera(CameraUpdateFactory .newLatLngZoom(new LatLng(-33.87365, 151.20689), 10)); } @Override public void onCameraMoveStarted(int reason) { if (reason == OnCameraMoveStartedListener.REASON_GESTURE) { Toast.makeText(this, "The user gestured on the map.", Toast.LENGTH_SHORT).show(); } else if (reason == OnCameraMoveStartedListener .REASON_API_ANIMATION) { Toast.makeText(this, "The user tapped something on the map.", Toast.LENGTH_SHORT).show(); } else if (reason == OnCameraMoveStartedListener .REASON_DEVELOPER_ANIMATION) { Toast.makeText(this, "The app moved the camera.", Toast.LENGTH_SHORT).show(); } } @Override public void onCameraMove() { Toast.makeText(this, "The camera is moving.", Toast.LENGTH_SHORT).show(); } @Override public void onCameraMoveCanceled() { Toast.makeText(this, "Camera movement canceled.", Toast.LENGTH_SHORT).show(); } @Override public void onCameraIdle() { Toast.makeText(this, "The camera has stopped moving.", Toast.LENGTH_SHORT).show(); } } 

Creé un FrameLayout vacío acodado encima del MapFragment en la disposición. A continuación, establecer un onTouchListener en esta vista para saber cuándo el mapa se ha tocado, pero devolver falsa para que el tacto se pasa al mapa.

 <FrameLayout android:id="@+id/map_touch_layer" android:layout_width="match_parent" android:layout_height="match_parent" /> mapTouchLayer.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Utils.logDebug(TAG, "Map touched!"); timeLastTouched = System.currentTimeMillis(); return false; // Pass on the touch to the map or shadow layer. } }); 

https://developers.google.com/maps/documentation/android/reference/com/google/android/gms/maps/GoogleMap.OnMapClickListener

Vea este enlace. Implemente la interfaz y rellene el método onMapClick() o lo que necesite y establezca onMapClickListener en la implementación correcta.

 public class YourActivity extends Activity implements OnMapClickListener { @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); ... my_map.setOnMapClickListener(this) ... } public void onMapClick (LatLng point) { // Do Something } } 

Gaucho tiene una gran respuesta, y al ver los muchos upvotes pensé que podría haber alguna necesidad de otra aplicación:

Lo necesitaba para usar un oyente para que pueda reaccionar en el tacto y no tiene que comprobarlo constantemente.

Puse todo en una clase que se puede utilizar de esta manera:

 mapFragment.setNonConsumingTouchListener(new TouchSupportMapFragment.NonConsumingTouchListener() { @Override public void onTouch(MotionEvent motionEvent) { switch (motionEvent.getActionMasked()) { case MotionEvent.ACTION_DOWN: // map is touched break; case MotionEvent.ACTION_UP: // map touch ended break; default: break; // use more cases if needed, for example MotionEvent.ACTION_MOVE } } }); 

Donde el mapfragment necesita ser del tipo TouchSupportMapFragment y en el layout xml esta línea es necesaria:

 <fragment class="de.bjornson.maps.TouchSupportMapFragment" ... 

Aquí está la clase:

 package de.bjornson.maps; import android.content.Context; import android.os.Bundle; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import com.google.android.gms.maps.SupportMapFragment; public class TouchSupportMapFragment extends SupportMapFragment { public View mOriginalContentView; public TouchableWrapper mTouchView; private NonConsumingTouchListener mListener; @Override public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) { mOriginalContentView = super.onCreateView(inflater, parent, savedInstanceState); mTouchView = new TouchableWrapper(getActivity()); mTouchView.addView(mOriginalContentView); return mTouchView; } @Override public View getView() { return mOriginalContentView; } public void setNonConsumingTouchListener(NonConsumingTouchListener listener) { mListener = listener; } public interface NonConsumingTouchListener { boolean onTouch(MotionEvent motionEvent); } public class TouchableWrapper extends FrameLayout { public TouchableWrapper(Context context) { super(context); } @Override public boolean dispatchTouchEvent(MotionEvent event) { if (mListener != null) { mListener.onTouch(event); } return super.dispatchTouchEvent(event); } } } 
  // Initializing markerPoints = new ArrayList<LatLng>(); // Getting reference to SupportMapFragment of the activity_main SupportMapFragment sfm = (SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map); // Getting Map for the SupportMapFragment map = sfm.getMap(); // Enable MyLocation Button in the Map map.setMyLocationEnabled(true); // Setting onclick event listener for the map map.setOnMapClickListener(new OnMapClickListener() { @Override public void onMapClick(LatLng point) { // Already two locations if(markerPoints.size()>1){ markerPoints.clear(); map.clear(); } // Adding new item to the ArrayList markerPoints.add(point); // Creating MarkerOptions MarkerOptions options = new MarkerOptions(); // Setting the position of the marker options.position(point); if(markerPoints.size()==1){ options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN)); }else if(markerPoints.size()==2){ options.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED)); } // Add new marker to the Google Map Android API V2 map.addMarker(options); // Checks, whether start and end locations are captured if(markerPoints.size() >= 2){ LatLng origin = markerPoints.get(0); LatLng dest = markerPoints.get(1); //Do what ever you want with origin and dest } } }); 

Para los amantes del mono :

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using Android.App; using Android.Content; using Android.OS; using Android.Runtime; using Android.Util; using Android.Views; using Android.Widget; using Android.Gms.Maps; namespace apcurium.MK.Booking.Mobile.Client.Controls { public class TouchableMap : SupportMapFragment { public View mOriginalContentView; public TouchableWrapper Surface; public override View OnCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) { mOriginalContentView = base.OnCreateView(inflater, parent, savedInstanceState); Surface = new TouchableWrapper(Activity); Surface.AddView(mOriginalContentView); return Surface; } public override View View { get { return mOriginalContentView; } } } public class TouchableWrapper: FrameLayout { public event EventHandler<MotionEvent> Touched; public TouchableWrapper(Context context) : base(context) { } public TouchableWrapper(Context context, IAttributeSet attrs) : base(context, attrs) { } public TouchableWrapper(Context context, IAttributeSet attrs, int defStyle) : base(context, attrs, defStyle) { } public override bool DispatchTouchEvent(MotionEvent e) { if (this.Touched != null) { this.Touched(this, e); } return base.DispatchTouchEvent(e); } } } 

@Gaucho MySupportMapFragment obviamente será utilizado por algún otro fargment o actividad (donde podría haber más elementos de vista que el fragmento de mapa). Entonces, ¿cómo se puede enviar este evento al siguiente fragmento donde se va a usar. ¿Necesitamos escribir una interfaz de nuevo para hacer eso?

Tengo una solución más simple que la TouchableWrapper y esto funciona con la última versión de play-services-maps:10.0.1 . Esta solución sólo utiliza los eventos de mapas y no utiliza vistas personalizadas. No utiliza funciones obsoletas y probablemente tendrá soporte para varias versiones.

Primero necesitas una variable flag que almacene si el mapa está siendo movido por una animación o por entrada del usuario (este código asume que cada movimiento de la cámara que no es activado por una animación es activado por el usuario)

 GoogleMap googleMap; boolean movedByApi = false; 

Tu fragmento o actividad debe implementar GoogleMap.OnMapReadyCallback , GoogleMap.CancelableCallback

 public class ActivityMap extends Activity implements OnMapReadyCallback, GoogleMap.CancelableCallback{ ... } 

Y esto te obliga a implementar los métodos onMapReady , onFinish , onCancel . Y el objeto googleMap en onMapReady debe establecer un eventlistener para mover la cámara

 @Override public void onMapReady(GoogleMap mMap) { //instantiate the map googleMap = mMap; [...] // <- set up your map googleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() { @Override public void onCameraMove() { if (movedByApi) { Toast.makeText(ActivityMap.this, "Moved by animation", Toast.LENGTH_SHORT).show(); [...] // <-- do something whe you want to handle api camera movement } else { Toast.makeText(ActivityMap.this, "Moved by user", Toast.LENGTH_SHORT).show(); [...] // <-- do something whe you want to handle user camera movement } } }); } @Override public void onFinish() { //is called when the animation is finished movedByApi = false; } @Override public void onCancel() { //is called when the animation is canceled (the user drags the map or the api changes to a ne position) movedByApi = false; } 

Y finalmente su beter si usted crea una función genérica para mover el mapa

 public void moveMapPosition(CameraUpdate cu, boolean animated){ //activate the flag notifying that the map is being moved by the api movedByApi = true; //if its not animated, just do instant move if (!animated) { googleMap.moveCamera(cu); //after the instant move, clear the flag movedByApi = false; } else //if its animated, animate the camera googleMap.animateCamera(cu, this); } 

O simplemente cada vez que mueva el mapa, active el indicador antes de la animación

 movedByApi = true; googleMap.animateCamera(cu, this); 

¡Espero que esto ayude!

  • No se pudo encontrar el estilo 'mapViewStyle' en el tema actual
  • Mapa de Android Marcas cruzadas
  • 75 marcadores en el mapa -> pérdidas de memoria -> OutOfMemoryException
  • Android - SupportMapFragment con GoogleMaps API 2.0 dando IllegalArgumentException
  • Dibuja un arco geográficamente preciso en un mapa para Android
  • No se puede evaluar el módulo 'react-native-maps': No se ha encontrado la configuración con el nombre 'default'
  • Clustering marcadores en android mapas v2
  • Mapas de azulejos isométricos en Android
  • No se puede encontrar com.google.android.maps en Eclipse
  • Mapas androide recubrimiento de círculo, dinámicamente cambiar el radio?
  • Doble toque -> Zoom en Android MapView?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.