Añadir límites al mapa para evitar pasar fuera de una región determinada
Mi aplicación muestra un mapa y quiero que los usuarios no puedan desplazarse por una región determinada. Así que estoy tratando de agregar límites pero hace que la aplicación se bloquee. Aquí está el código de trabajo:
public class MapViewer extends Activity implements OnInfoWindowClickListener { private LatLng defaultLatLng = new LatLng(42.564241, 12.22759); private GoogleMap map; private int zoomLevel = 5; private Database db = new Database(this); protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.mapviewer); try { map = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap(); if (map != null) { map.setMyLocationEnabled(true); map.setMapType(GoogleMap.MAP_TYPE_NORMAL); map.getUiSettings().setRotateGesturesEnabled(false); map.moveCamera(CameraUpdateFactory.newLatLngZoom(defaultLatLng, zoomLevel)); this.addMerchantMarkers(new MarkerOptions()); map.setOnInfoWindowClickListener(this); } } catch (NullPointerException e) { e.printStackTrace(); } } @Override public void onPause() { if (map != null) { map.setMyLocationEnabled(false); map.setTrafficEnabled(false); } super.onPause(); } public void addMerchantMarkers(MarkerOptions mo) { SQLiteDatabase dbRead = db.getReadableDatabase(); String[] columns = {"title", "addr", "lat", "lon"}; Cursor result = dbRead.query("merchants", columns, null, null, null, null, null); while(result.moveToNext()) { String merchant = result.getString(0); String address = result.getString(1); float lat = result.getFloat(2); float lon = result.getFloat(3); LatLng pos = new LatLng(lat, lon); map.addMarker(mo.position(pos) .title(merchant) .snippet(address) .icon(BitmapDescriptorFactory.fromResource(R.drawable.marker_50)));; } } }
Y este es el código que agrego en el método onCreate que causa el accidente:
- Cómo invertir Geocode en google maps api 2 android
- Cómo determinar si las coordenadas largas del lat están en una carretera con Google Maps API v2
- El método de instantánea de GoogleMap devuelve una imagen blanca
- Android Google Maps v2 - Añadir objeto al marcador
- SupportMapFragment.getmap () devuelve null
LatLngBounds.Builder builder = new LatLngBounds.Builder(); builder.include(new LatLng(47.09194444, 18.52166666)); builder.include(new LatLng(36.448311, 6.62555555)); LatLngBounds bounds = builder.build(); CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, 30); map.animateCamera(cu);
Aquí está el LogCat:
08-10 20:59:41.689: E/AndroidRuntime(6304): FATAL EXCEPTION: main 08-10 20:59:41.689: E/AndroidRuntime(6304): Process: com.example.myapp, PID: 6304 08-10 20:59:41.689: E/AndroidRuntime(6304): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.myapp/com.example.myapp.MapViewer}: java.lang.IllegalStateException: Error using newLatLngBounds(LatLngBounds, int): Map size can't be 0. Most likely, layout has not yet occured for the map view. Either wait until layout has occurred or use newLatLngBounds(LatLngBounds, int, int, int) which allows you to specify the map's dimensions. 08-10 20:59:41.689: E/AndroidRuntime(6304): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2215) 08-10 20:59:41.689: E/AndroidRuntime(6304): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2264) 08-10 20:59:41.689: E/AndroidRuntime(6304): at android.app.ActivityThread.access$800(ActivityThread.java:144) 08-10 20:59:41.689: E/AndroidRuntime(6304): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1205) 08-10 20:59:41.689: E/AndroidRuntime(6304): at android.os.Handler.dispatchMessage(Handler.java:102) 08-10 20:59:41.689: E/AndroidRuntime(6304): at android.os.Looper.loop(Looper.java:136) 08-10 20:59:41.689: E/AndroidRuntime(6304): at android.app.ActivityThread.main(ActivityThread.java:5139) 08-10 20:59:41.689: E/AndroidRuntime(6304): at java.lang.reflect.Method.invokeNative(Native Method) 08-10 20:59:41.689: E/AndroidRuntime(6304): at java.lang.reflect.Method.invoke(Method.java:515) 08-10 20:59:41.689: E/AndroidRuntime(6304): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:796) 08-10 20:59:41.689: E/AndroidRuntime(6304): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:612) 08-10 20:59:41.689: E/AndroidRuntime(6304): at dalvik.system.NativeStart.main(Native Method) 08-10 20:59:41.689: E/AndroidRuntime(6304): Caused by: java.lang.IllegalStateException: Error using newLatLngBounds(LatLngBounds, int): Map size can't be 0. Most likely, layout has not yet occured for the map view. Either wait until layout has occurred or use newLatLngBounds(LatLngBounds, int, int, int) which allows you to specify the map's dimensions. 08-10 20:59:41.689: E/AndroidRuntime(6304): at mut.b(Unknown Source) 08-10 20:59:41.689: E/AndroidRuntime(6304): at oxp.a(Unknown Source) 08-10 20:59:41.689: E/AndroidRuntime(6304): at oxi.a(Unknown Source) 08-10 20:59:41.689: E/AndroidRuntime(6304): at oyf.b(Unknown Source) 08-10 20:59:41.689: E/AndroidRuntime(6304): at grl.onTransact(SourceFile:92) 08-10 20:59:41.689: E/AndroidRuntime(6304): at android.os.Binder.transact(Binder.java:361) 08-10 20:59:41.689: E/AndroidRuntime(6304): at com.google.android.gms.maps.internal.IGoogleMapDelegate$a$a.animateCamera(Unknown Source) 08-10 20:59:41.689: E/AndroidRuntime(6304): at com.google.android.gms.maps.GoogleMap.animateCamera(Unknown Source) 08-10 20:59:41.689: E/AndroidRuntime(6304): at com.example.myapp.MapViewer.onCreate(MapViewer.java:59) 08-10 20:59:41.689: E/AndroidRuntime(6304): at android.app.Activity.performCreate(Activity.java:5231) 08-10 20:59:41.689: E/AndroidRuntime(6304): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087) 08-10 20:59:41.689: E/AndroidRuntime(6304): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2169) 08-10 20:59:41.689: E/AndroidRuntime(6304): ... 11 more
- Android Maps - el método animateCamera () no funciona correctamente
- Cómo agregar controles personalizados a MapFragment en Google Maps Android API v2?
- BadParcelableException en el código de google maps
- ¿Cómo descargar Google Play Services en un emulador de Android?
- Refreshing makers (ClusterItems) en Google Maps v2 para Android
- Hacer TileOverlays transparente
- Google Maps Android: el mapa de repente no se muestra
- Mapa de MapFragment se carga con lag cuando regrese de otra actividad
Puede utilizar MapLoadedCallBack;
map.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() { @Override public void onMapLoaded() { map.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 30)); } });
Y también puedes usar este evento que ocurre antes de arriba.
map.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() { @Override public void onCameraChange(CameraPosition arg0) { map.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 30)); } });
Puede evitar que se produzca el error siguiendo el consejo del registro:
"… use newLatLngBounds (LatLngBounds, int, int, int) que le permite especificar las dimensiones del mapa."
Los parámetros adicionales son el ancho y la altura de la pantalla. Así es como se vería el código actualizado:
LatLngBounds.Builder builder = new LatLngBounds.Builder(); builder.include(new LatLng(47.09194444, 18.52166666)); builder.include(new LatLng(36.448311, 6.62555555)); LatLngBounds bounds = builder.build(); // begin new code: int width = getResources().getDisplayMetrics().widthPixels; int height = getResources().getDisplayMetrics().heightPixels; int padding = (int) (width * 0.12); // offset from edges of the map 12% of screen CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, width, height, padding); // end of new code map.animateCamera(cu);
Causado por: java.lang.IllegalStateException: Error al usar newLatLngBounds (LatLngBounds, int): El tamaño del mapa no puede ser 0. Lo más probable es que aún no se haya producido la vista del mapa. Espere hasta que se haya producido el diseño o utilice newLatLngBounds (LatLngBounds, int, int, int) que le permite especificar las dimensiones del mapa.
Desde los documentos https://developer.android.com/reference/com/google/android/gms/maps/CameraUpdateFactory.html#newLatLngBounds(com.google.android.gms.maps.model.LatLngBounds , int)
No cambie la cámara con esta actualización de cámara hasta que el mapa se haya sometido a diseño (para que este método determine correctamente el cuadro delimitador y el nivel de zoom adecuados, el mapa debe tener un tamaño). De lo contrario se lanzará una IllegalStateException. No es suficiente que el mapa esté disponible (es decir, getMap () devuelve un objeto no nulo); La vista que contiene el mapa debe haberse sometido también a una disposición tal que se hayan determinado sus dimensiones. Si no puede estar seguro de que esto ha ocurrido, utilice newLatLngBounds (LatLngBounds, int, int, int) y proporcione las dimensiones del mapa manualmente.
Nota: getMap()
podría devolver null. Es mejor comprobar la disponibilidad de los servicios de reproducción de Google antes de inicializar el objeto GoogleMap.
Caused by: java.lang.IllegalStateException: Map size should not be 0. Most likely, layout has not yet occured for the map view.
La razón detrás de este error es porque el diseño del mapa no se ha completado, Debe implementar OnMapReadyCallback en sus llamadas, lo que garantizará que su código sólo se ejecutará después de su diseño se ha completado o Implementar la devolución de llamada a continuación
map.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() { @Override public void onCameraChange(CameraPosition arg0) { map.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 30)); } });
Enlaces duplicados
MoveCamera con CameraUpdateFactory.newLatLngBounds se bloquea
El tamaño del mapa IllegalStateException no debe ser 0
No lo sé si hay una manera de fusionar este enlace. Espero que ayudara
La documentación de onMapReady () indica claramente que hay que esperar a que tanto onMapReadyCallback como ViewTreeObserver.OnGlobalLayoutListener:
Tenga en cuenta que esto no garantiza que el mapa haya sido modificado. Por lo tanto, el tamaño del mapa puede no haber sido determinado por el momento se llama el método de devolución de llamada. Si necesita conocer las dimensiones o llamar a un método en la API que necesita conocer las dimensiones, obtenga la vista del mapa y registre un ViewTreeObserver.OnGlobalLayoutListener también.
Es bastante inconveniente, pero una forma de hacerlo sería mediante el uso de RxJava. Podrías emitir dos observables, primero en onMapReady y segundo en onGlobalLayout, luego rellenarlos juntos y hacer lo que tengas que hacer. De esta manera usted puede estar seguro de que ambos devoluciones fueron despedidos.
Coloque la llamada dentro de un runnable y colóquela en el manejador de vistas, así:
mapFragment.getView().post(new Runnable() { @Override public void run() { map.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds.build(), CAMERA_PADDING)); } });
Cuando se ha establecido la vista, el runnable ejecutará y posicionará correctamente el mapa. El problema con ahmadalibalochs respuesta, es que usted verá un destello del mundo antes de que se posicione correctamente. Publicarlo en el controlador de vista, resuelve este problema.
He creado una forma de combinar las dos devoluciones de llamada: onMapReady y onGlobalLayout en un único observable que emitirá sólo cuando ambos eventos hayan sido activados.
https://gist.github.com/abhaysood/e275b3d0937f297980d14b439a8e0d4a
public final class OnMapAndLayoutReady { private OnMapAndLayoutReady() { } /** * Converts {@link OnMapReadyCallback} to an observable. * Note that this method calls {@link MapView#getMapAsync(OnMapReadyCallback)} so you there is no * need to initialize google map view manually. */ private static Observable<GoogleMap> loadMapObservable(final MapView mapView) { return Observable.create(new Observable.OnSubscribe<GoogleMap>() { @Override public void call(final Subscriber<? super GoogleMap> subscriber) { OnMapReadyCallback mapReadyCallback = new OnMapReadyCallback() { @Override public void onMapReady(GoogleMap googleMap) { subscriber.onNext(googleMap); } }; mapView.getMapAsync(mapReadyCallback); } }); } /** * Converts {@link ViewTreeObserver.OnGlobalLayoutListener} to an observable. * This methods also takes care of removing the global layout listener from the view. */ private static Observable<MapView> globalLayoutObservable(final MapView view) { return Observable.create(new Observable.OnSubscribe<MapView>() { @Override public void call(final Subscriber<? super MapView> subscriber) { final ViewTreeObserver.OnGlobalLayoutListener globalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { view.getViewTreeObserver().removeOnGlobalLayoutListener(this); subscriber.onNext(view); } }; view.getViewTreeObserver().addOnGlobalLayoutListener(globalLayoutListener); } }); } /** * Takes {@link #globalLayoutObservable(MapView)} and {@link #loadMapObservable(MapView)} and zips their result. * This means that the subscriber will only be notified when both the observables have emitted. */ public static Observable<GoogleMap> onMapAndLayoutReadyObservable(final MapView mapView) { return Observable.zip(globalLayoutObservable(mapView), loadMapObservable(mapView), new Func2<MapView, GoogleMap, GoogleMap>() { @Override public GoogleMap call(MapView mapView, GoogleMap googleMap) { return googleMap; } }); } }
Esto funcionó para mí:
@Override protected void onCreate(Bundle savedInstanceState) { ... mMapFragment.getMapAsync(this); } @Override public void onMapReady(GoogleMap googleMap) { mMapFragment.getView().getViewTreeObserver().addOnGlobalLayoutListener(this); } @Override public void onGlobalLayout() { mMapFragment.getView().getViewTreeObserver().removeOnGlobalLayoutListener(this); //Only after onMapReady & onGlobalLayout newLatLngBounds will be available initMapPosition(); //newLatLngBounds here }
- Los elementos ListView no se pueden hacer clic. ¿por qué?
- Inicio de la actividad mediante la acción personalizada