ver usar studio simbologia programacion nombres las google geolocalizacion etiquetas como celular calles android google-maps android-mapview google-maps-android-api-2

usar - ¿Cómo puedo manejar el movimiento del mapa usando Google Maps para Android V2?



manual de programacion android pdf (11)

Quiero geocodificar la dirección tan pronto como se haya cambiado el centro del mapa.

¿Cómo puedo manejar el movimiento del mapa con los nuevos Google Maps para Android V2? (Estoy hablando del caso, entonces el usuario arrastra el mapa con el dedo)


Aquí hay una posible solución para determinar los eventos de inicio de arrastre y fin de arrastre:

Debe extender SupportMapFragment o MapFragment. En onCreateView tienes que ajustar tu MapView en un FrameLayout personalizado (en el ejemplo siguiente, es la clase "TouchableWrapper"), en el que interceptas eventos táctiles y reconoces si el mapa está intervenido o no. Si se llama a su "onCameraChange", simplemente verifique si la vista del mapa está presionada o no (en el ejemplo a continuación, esta es la variable "mMapIsTouched").

Código de ejemplo:

ACTUALIZACIÓN 1:

  • devolver la vista original creada en getView ()
  • utilice dispatchTouchEvent () en lugar de onInterceptTouchEvent ()

FrameLayout personalizado:

private class TouchableWrapper extends FrameLayout { @Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mMapIsTouched = true; break; case MotionEvent.ACTION_UP: mMapIsTouched = false; break; } return super.dispatchTouchEvent(ev); } }

En su MapFragment personalizado:

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

En su cámara, cambie el método de devolución de llamada:

private final OnCameraChangeListener mOnCameraChangeListener = new OnCameraChangeListener() { @Override public void onCameraChange(CameraPosition cameraPosition) { if (!mMapIsTouched) { refreshClustering(false); } } };


Comenzando con play-services-maps 9.4.0 puede simplemente usar GoogleMap.OnCameraMoveStartedListener , GoogleMap.OnCameraMoveListener y GoogleMap.OnCameraIdleListener .

Si, por algún motivo, desea utilizar la API anterior, que ahora está en desuso, puede usar onCameraChangeListener . Pero debes ser consciente de dos cosas:

  1. onCameraChange() se puede llamar varias veces mientras se arrastra el mapa O solo una vez (cuando se detiene el arrastre).
  2. La posición de la cámara en la última llamada de onCameraChange() puede ser ligeramente diferente de la posición final de la cámara.

El siguiente código tiene en cuenta ambos problemas:

private static final int MESSAGE_ID_SAVE_CAMERA_POSITION = 1; private static final int MESSAGE_ID_READ_CAMERA_POSITION = 2; private CameraPosition lastCameraPosition; private Handler handler; private GoogleMap googleMap; public void onMapReady(GoogleMap theGoogleMap) { googleMap = theGoogleMap; handler = new Handler() { public void handleMessage(Message msg) { if (msg.what == MESSAGE_ID_SAVE_CAMERA_POSITION) { lastCameraPosition = googleMap.getCameraPosition(); } else if (msg.what == MESSAGE_ID_READ_CAMERA_POSITION) { if (lastCameraPosition.equals(googleMap.getCameraPosition())) { Log.d(LOG, "Camera position stable"); } } } }; googleMap.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() { @Override public void onCameraChange(CameraPosition cameraPosition) { handler.removeMessages(MESSAGE_ID_SAVE_CAMERA_POSITION); handler.removeMessages(MESSAGE_ID_READ_CAMERA_POSITION); handler.sendEmptyMessageDelayed(MESSAGE_ID_SAVE_CAMERA_POSITION, 300); handler.sendEmptyMessageDelayed(MESSAGE_ID_READ_CAMERA_POSITION, 600); } }); }


Creo que el evento onclick en el mapa es: map.setOnMapClick ... Pero el evento de arrastre es: map.onCameraChangeListener porque invoco un log.e en ambas funciones y se muestra como onClick view y onDrag view. Así que solo los usa para ti.


Después de utilizar la solución de AZ13 anterior, y al encontrar el problema mencionado en los comentarios, creé la siguiente solución, que resuelve el problema de manera más confiable. Sin embargo, dado que estoy usando un temporizador después del evento onRelease para determinar si el mapa todavía está animando, hay un ligero retraso en esta solución.

El código se puede encontrar en Github a través de este enlace: https://github.com/MadsFrandsen/MapStateListener

Mi solución se puede usar a partir de una actividad de la siguiente manera:

new MapStateListener(mMap, mMapFragment, this) { @Override public void onMapTouched() { // Map touched } @Override public void onMapReleased() { // Map released } @Override public void onMapUnsettled() { // Map unsettled } @Override public void onMapSettled() { // Map settled } };


Echa un vistazo a la nueva API de mapas.

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

muestra developers.google.com


La forma más sencilla es utilizar el método setOnCameraIdleListener para manejar el estado de final de movimiento del detector táctil en el fragmento del mapa. mira el ejemplo a continuación:

mMap.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() { @Override public void onCameraMoveStarted(int i) { mapPin.startAnimation(animZoomOut); } }); mMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() { @Override public void onCameraIdle() { mapPin.startAnimation(animZoomIn); } });


Solución mejorada con un Handler inner Class en Xamarin Android, basado en la respuesta de Tobus:

public void OnMapReady(GoogleMap googleMap) { _googleMap = googleMap; if (_googleMap != null) { _cameraPositionHandler = new CameraPositionlHandler(_googleMap); _googleMap.CameraChange += OnCameraChanged; } } void OnCameraChanged (object sender, GoogleMap.CameraChangeEventArgs e) { _cameraPositionHandler.RemoveMessages(MESSAGE_ID_SAVE_CAMERA_POSITION); _cameraPositionHandler.RemoveMessages(MESSAGE_ID_READ_CAMERA_POSITION); _cameraPositionHandler.SendEmptyMessageDelayed(MESSAGE_ID_SAVE_CAMERA_POSITION, 300); _cameraPositionHandler.SendEmptyMessageDelayed(MESSAGE_ID_READ_CAMERA_POSITION, 600); }

Con la siguiente clase interna:

private class CameraPositionlHandler : Handler { private CameraPosition _lastCameraPosition; private GoogleMap _googleMap; public CameraPositionlHandler (GoogleMap googleMap) { _googleMap = googleMap; } public override void HandleMessage(Message msg) { if (_googleMap != null) { if (msg.What == MESSAGE_ID_SAVE_CAMERA_POSITION) { _lastCameraPosition = _googleMap.CameraPosition; } else if (msg.What == MESSAGE_ID_READ_CAMERA_POSITION) { if (_lastCameraPosition.Equals(_googleMap.CameraPosition)) { Console.WriteLine("Camera position stable"); //do what you want } } } } }


Tengo que animar mi marcador para centrarme mientras el usuario arrastre el mapa. Lo he implementado usando la respuesta de Stas Shakirov

MapDragListenerFragment.class

public class MapDragListenerFragment extends Fragment implements OnMapReadyCallback, GoogleMap.OnMapLoadedCallback { private Context mContext; private SupportMapFragment supportMapFragment; private Marker centerMarker; private LatLng mapCenterLatLng; private TextView tvLocationName; private Button btnFinalizeDestination; private GoogleMap mGoogleMap; @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_map_drag_listener, container, false); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); mContext = getActivity(); tvLocationName = (TextView) view.findViewById(R.id.tv_location_name); } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); FragmentManager fm = getActivity().getSupportFragmentManager();//getChildFragmentManager();// supportMapFragment = (SupportMapFragment) fm.findFragmentById(R.id.map_container); if (supportMapFragment == null) { //// FIXME: 2/13/2017 crashes at casting to TouchableMapFragment supportMapFragment = SupportMapFragment.newInstance(); fm.beginTransaction().replace(R.id.map_container, supportMapFragment).commit(); } supportMapFragment.getMapAsync(this); } @Override public void onMapReady(GoogleMap googleMap) { if (googleMap != null) { mGoogleMap = googleMap; centerMarker = mGoogleMap.addMarker(new MarkerOptions().position(mGoogleMap.getCameraPosition().target) .title("Center of Map") .icon(BitmapDescriptorFactory.fromResource(R.drawable.end_green))); mGoogleMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() { @Override public void onCameraIdle() { mapCenterLatLng = mGoogleMap.getCameraPosition().target; animateMarker(centerMarker,mapCenterLatLng,false); Toast.makeText(mContext, "The camera has stopped moving.", Toast.LENGTH_SHORT).show(); String address = getCompleteAddressString(mapCenterLatLng.longitude,mapCenterLatLng.longitude); tvLocationName.setText(address); } }); mGoogleMap.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() { @Override public void onCameraMoveStarted(int reason) { if (reason == GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE) { ///tvLocationName.setText("Lat " + mapCenterLatLng.latitude + " Long :" + mapCenterLatLng.longitude); Toast.makeText(mContext, "The user gestured on the map.", Toast.LENGTH_SHORT).show(); } else if (reason == GoogleMap.OnCameraMoveStartedListener .REASON_API_ANIMATION) { Toast.makeText(mContext, "The user tapped something on the map.", Toast.LENGTH_SHORT).show(); } else if (reason == GoogleMap.OnCameraMoveStartedListener .REASON_DEVELOPER_ANIMATION) { Toast.makeText(mContext, "The app moved the camera.", Toast.LENGTH_SHORT).show(); } } }); mGoogleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() { @Override public void onCameraMove() { Toast.makeText(mContext, "The camera is moving.", Toast.LENGTH_SHORT).show(); } }); mGoogleMap.setOnCameraMoveCanceledListener(new GoogleMap.OnCameraMoveCanceledListener() { @Override public void onCameraMoveCanceled() { Toast.makeText(mContext, "Camera movement canceled.", Toast.LENGTH_SHORT).show(); } }); mapCenterLatLng = mGoogleMap.getCameraPosition().target;// it should be done on MapLoaded. if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; } mGoogleMap.setMyLocationEnabled(true); mGoogleMap.animateCamera(CameraUpdateFactory.zoomTo(15)); mGoogleMap.setOnMapLoadedCallback(this); mGoogleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() { @Override public void onCameraMove() { } }); } } public void animateMarker(final Marker marker, final LatLng toPosition, final boolean hideMarker) { final Handler handler = new Handler(); final long start = SystemClock.uptimeMillis(); Projection proj = mGoogleMap.getProjection(); Point startPoint = proj.toScreenLocation(marker.getPosition()); final LatLng startLatLng = proj.fromScreenLocation(startPoint); final long duration = 500; final Interpolator interpolator = new LinearInterpolator(); handler.post(new Runnable() { @Override public void run() { long elapsed = SystemClock.uptimeMillis() - start; float t = interpolator.getInterpolation((float) elapsed / duration); double lng = t * toPosition.longitude + (1 - t) * startLatLng.longitude; double lat = t * toPosition.latitude + (1 - t) * startLatLng.latitude; marker.setPosition(new LatLng(lat, lng)); if (t < 1.0) { // Post again 16ms later. handler.postDelayed(this, 16); } else { if (hideMarker) { marker.setVisible(false); } else { marker.setVisible(true); } } } }); } }

donde fragment_map_drag_listener.xml

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <RelativeLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"> <fragment android:id="@+id/map_container" android:name="com.google.android.gms.maps.SupportMapFragment" android:layout_width="match_parent" android:layout_height="match_parent" /> <ImageView android:id="@+id/iv_center_overlay" android:layout_width="25dp" android:layout_height="25dp" android:visibility="gone" android:layout_centerInParent="true" android:src="@drawable/start_blue" /> </RelativeLayout> <TextView android:id="@+id/tv_location_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="4dp" android:text="Location Name" /> </LinearLayout>

donde MapDragListenerActivity

public class MapDragListenerActivity extends AppCompatActivity { private Context mContext; private static final String TAG = MapDragListenerFragment.class.getSimpleName(); private MapDragListenerFragment mapDragListenerFragment; private Button selectPlaceBtn; public static final int PLACE_AUTOCOMPLETE_REQUEST_CODE = 1219; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_map_drag_listener); mContext = MapDragListenerActivity.this; mapDragListenerFragment = new MapDragListenerFragment(); getSupportFragmentManager().beginTransaction() .replace(R.id.frame_container,//where frame_container is a FrameLayout mapDragListenerFragment, MapyFragment.class.getSimpleName()).commit(); selectPlaceBtn = (Button) findViewById(R.id.btn_select_place); selectPlaceBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { try { Intent intent = new PlaceAutocomplete.IntentBuilder( PlaceAutocomplete.MODE_FULLSCREEN).build(MapDragListenerActivity.this); startActivityForResult(intent, PLACE_AUTOCOMPLETE_REQUEST_CODE); } catch (GooglePlayServicesRepairableException e) { e.printStackTrace(); } catch (GooglePlayServicesNotAvailableException e) { e.printStackTrace(); } } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if(requestCode == PLACE_AUTOCOMPLETE_REQUEST_CODE){ if (resultCode == RESULT_OK) { Place place = PlaceAutocomplete.getPlace(mContext, data); if(mapDragListenerFragment != null && mapDragListenerFragment.isVisible()) mapDragListenerFragment.updateMarkerAtPosition( place.getLatLng() ,place.getName().toString()); Log.i(TAG, "Place:" + place.toString()); } else if (resultCode == PlaceAutocomplete.RESULT_ERROR) { Status status = PlaceAutocomplete.getStatus(mContext, data); Log.i(TAG, status.getStatusMessage()); } else if (requestCode == RESULT_CANCELED) { } } } }

activity_map_drag_listener.xml

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <Button android:id="@+id/btn_select_place" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Select Place" /> <FrameLayout android:id="@+id/frame_container" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>


Yo probaría onCameraChangeListener . Se llama al oyente cada vez que finaliza un movimiento de la cámara. El oyente también le dará la nueva ubicación. En mis pruebas, el oyente fue llamado con bastante frecuencia durante el arrastre, tal vez haya una mejor solución.


En la cámara inactiva es lo que debe usar ahora

googleMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() { @Override public void onCameraIdle() { //Called when camera movement has ended, there are no pending animations and the user has stopped interacting with the map. } });


@Override public boolean onTouchEvent(MotionEvent event, MapView mapView){ if(event.getAction() == MotionEvent.ACTION_MOVE) return true; return false; }