proyecto para mapas google agregar android google-maps maps touch google-maps-api-2

mapas - maps sdk para android



Google Maps Android API v2: detección táctil en el mapa (10)

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

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


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


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

Esa solución parece ser una solución posible, pero el código sugerido era incompleto. Por esta razón lo reescribí 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" />

Solo para prueba en la Actividad principal, escribí solo lo 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í hay una solución simple para obtener la ubicación basada en la selección del usuario (haga clic en la opción en el mapa)

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


Creé un FrameLayout vacío en capas sobre la parte superior de MapFragment en el diseño. Luego configuré un onTouchListener en esta vista, así sé cuándo se ha tocado el mapa, pero se devuelve falso para que el toque se pase 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. } });


Esta característica y muchas más ahora son compatibles :)

esta es la nota del desarrollador (Problema 4636):

La publicación de agosto de 2016 presenta un conjunto de nuevos oyentes de cambio de cámara para el inicio de movimiento de la cámara, eventos continuos y finales. También puede ver por qué la cámara se está moviendo, ya sea causada por gestos de usuario, animaciones API incorporadas o movimientos controlados por el desarrollador. Para obtener detalles, consulte la guía de eventos de cambio de cámara: https://developers.google.com/maps/documentation/android-api/events#camera-change-events

Además, consulte 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(); } }


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

Necesitaba usar un oyente para poder reaccionar al tacto y no tener que revisarlo constantemente.

Puse todo en una clase que se puede usar así:

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); } } }


Para los amantes de 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); } } }


Tengo una solución más simple diferente al TouchableWrapper y esto funciona con la última versión de play-services-maps:10.0.1 . Esta solución solo usa los eventos de mapas y no usa vistas personalizadas. No usa funciones en desuso y es probable que tenga soporte para varias versiones.

Primero necesita una variable de marcador que se almacena si el mapa está siendo movido por una animación o por la entrada del usuario (este código asume que el movimiento desencadena cada movimiento de la cámara que no se desencadena por una animación)

GoogleMap googleMap; boolean movedByApi = false;

Su estructura 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 es mejor si creas 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 solo cada vez que mueves el mapa, activa la bandera antes de la animación

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

¡Espero que esto ayude!


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

Ver este enlace Implemente la interfaz y complete el método onMapClick() o lo que necesite y configure 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 } }


// 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 } } });