Mover MapFragment (SurfaceView) hace que el fondo negro parpadee

Estoy intentando implementar la nueva API de Google Maps de Google (v2). Sin embargo, no parece ir bien con SlidingMenu . Como puede saber, la implementación de MapFragment se basa en SurfaceView . El problema es que el SurfaceView no tiene gusto de moverse alrededor – me refiero a colocarlo en vistas movibles:

  • ViewPager ,
  • ScrollView ,
  • ListView ,
  • O el mencionado SlidingMenu .

Cuando se mueve, deja un agujero negro en el lugar donde sus píxeles originalmente establecidos. Parece algo así.

Este problema se puede resolver parcialmente especificando un fondo transparente en SurfaceView o incluso colocando una View transparente sobre él. Simplemente no puedo imaginar si sólo para mí los resultados son inaceptables, o si tengo un problema diferente que hace que se vea cómo se ve.

Para ver cómo se ve, por favor, ver este video .

(Lo siento por la calidad, pero el problema se puede ver fácilmente de todos modos)

Cuando una vista normal de la lista (la pantalla naranja) es retirada mientras se abre SlidingMenu , la animación es suave y agradable. Pero tan pronto como aparece el MapFragment , hay algún extraño problema de actualización / parpadeo / sincronización en el mapa.

Probado en HTC One S y Samsung Galaxy ACE.


Mi idea super-duper-loca de resolverlo: cada vez que se inicia la animación de apertura, tomar una captura de pantalla del MapFragment (debería ser posible con SurfaceView) y ponerlo durante la duración de la animación. Pero realmente no sé cómo hacerlo … Tomar una captura de pantalla de un mapa no es posible , pero tal vez alguien se inspire en esto.

O tal vez deshabilitar el redibujo del mapa de otra manera, no lo sé.


ACTUALIZAR:

Encontré esto .

Parece que SurfaceView se puede cambiar a TextureView para eliminar esas limitaciones. Pero como MapFragment se basa en SurfaceView, no sé si se puede lograr.

Otra actualización Parece que este problema se ha resuelto en dispositivos 4.1+. Acaban de usar TextureView. Pero en las versiones inferiores todavía tenemos que usar soluciones alternativas.

Por supuesto, la solución adecuada será que Google solucione el problema (consulte el tema 4639 de Android Maps V2: http://code.google.com/p/gmaps-api-issues/issues/detail?id=4639 ).

Sin embargo, uno de mis compañeros de trabajo sugirió simplemente extender el mapa más allá de su contenedor. Si extendemos el fragmento del mapa más allá de la región visible de su contenedor, así:

 android:layout_marginLeft="-40dp" android:layout_marginRight="-40dp" 

Podemos reducir / eliminar el parpadeo. Los dispositivos más recientes (por ejemplo, Galaxy Nexus) no muestran parpadeos después de este truco, y los dispositivos más antiguos (por ejemplo, LG Optimus V) muestran un parpadeo reducido. Tenemos que extender los márgenes en ambos lados para que las ventanas de información se centren cuando se seleccionan.


Actualización: Este problema fue corregido por Google el 28 de agosto, pero supongo que todavía tiene que ser lanzado en una versión.

Puede utilizar esta biblioteca

https://github.com/NyxDigital/NiceSupportMapFragment/

Esto funciona bien para mi.

Aquí está una idea loca, no mueva el MapView 😉

Es decir, cree un ancho de pantalla completa MapView detrás de su aplicación en FrameLayout. A continuación, coloque sus puntos de vista en la parte superior y perforar un agujero a través de la MapView en la posición que necesita para mostrarlo. Cuando se mueva tendrá que actualizar la posición del mapa para mantenerse en sincronía para que el usuario siga viendo la misma sección del mapa, pero que debe actualizarse mejor que mover una vista de superficie alrededor.

Bueno, citando a Dianne Hackborn (un ingeniero de framework de Android)

La vista de la superficie es en realidad detrás de su ventana, y un agujero perforado en la ventana para que usted lo vea. Usted puede así poner las cosas encima de él en su ventana, pero nada en su ventana puede aparecer detrás de él. Puesto original

Esta arquitectura es parte de por qué usted ve estos parpadeos.

Algunos parpadeo a veces aparecen debido a doble buffers: Android codificación blog explica más .

También puede probar y subclase el SurfaceView para tratar de dibujar el fondo de manera diferente. No he visto un ejemplo de esto que no cambia el índice z que es el de la parte superior. Echa un vistazo a este mensaje de SO

De lo contrario, recomiendo sólo obtener el SurfaceHolder después de que su vista se centra (intentar y hacer una vista temporal hasta entonces) y la eliminación de la SurfaceView mientras no en el enfoque y en la pantalla.

Tomar una captura de pantalla de un mapa no es posible, pero tal vez alguien se inspire en esto.

Es posible con la interfaz de instantánea de GoogleMap . Ahora puede mostrar una instantánea del mapa mientras desplaza la página. Con esto resolví mi problema con ViewPager, quizás usted puede cambiar el código para caber su SlidingMenu.

Aquí está mi código para configurar la instantánea (está en el mismo fragmento que el mapa, llamado FragmentMap.java):

 public void setSnapshot(int visibility) { switch(visibility) { case View.GONE: if(mapFragment.getView().getVisibility() == View.VISIBLE) { getMap().snapshot(new SnapshotReadyCallback() { @Override public void onSnapshotReady(Bitmap arg0) { iv.setImageBitmap(arg0); } }); iv.setVisibility(View.VISIBLE); mapFragment.getView().setVisibility(View.GONE); } break; case View.VISIBLE: if(mapFragment.getView().getVisibility() == View.GONE) { mapFragment.getView().setVisibility(View.VISIBLE); iv.setVisibility(View.GONE); } break; } } 

Donde "mapFragment" es mi SupportedMapFragment y "iv" es un ImageView (lo hace match_parent).

Y aquí estoy controlando el rollo:

 pager.setOnPageChangeListener(new OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { if(position == 0 && positionOffsetPixels > 0 || position == 1 && positionOffsetPixels > 0) { ((FragmentMap)adapter.getRegisteredFragment(1)).setSnapshot(View.GONE); } else if(position == 1 && positionOffsetPixels == 0) { ((FragmentMap)adapter.getRegisteredFragment(1)).setSnapshot(View.VISIBLE); } } @Override public void onPageScrollStateChanged(int arg0) {} @Override public void onPageSelected(int arg0) {} }); 

Mi fragmento con el mapa (FragmentMap) está en la posición 1, así que necesito controlar el desplazamiento de la posición 0 a 1 y de la posición 1 a 2 (la primera si-cláusula). "GetRegisteredFragment ()" es una función en mi FragmentPagerAdapter personalizado, en el que tengo un SparseArray (Fragmento) llamado "registeredFragments".

Por lo tanto, siempre que desplácese hacia o desde su mapa, siempre verá una instantánea de la misma. Esto funciona muy bien para mí.

En mi escenario, tuve un Fragmento inicial, que en un clic de botón cambió en un segundo fragmento con un MapFragment dentro de él. Me di cuenta de que este parpadeo sólo se produjo la primera vez que cambiar el fragmento – haciendo estallar la pila de atrás, y el intercambio en otro fragmento del mismo tipo no causó un parpadeo.

Así que imaginar que tenía algo que ver con la adición de un SurfaceView inicial a la ventana, he intentado agregar una instancia vacía de un SurfaceView a mi fragmento cargado inicialmente, detrás de su vista principal. Y el bingo, no más parpadeo al animar en el siguiente fragmento!

Sé que no es la solución más limpia, pero funciona. El MapFragment de Google (o SupportMapFragment en mi caso) sigue funcionando bien, ya que SurfaceView no se encuentra en el fragmento anterior.

Debo añadir que estoy usando la API v2.

Actualizar @VenomVendor

Añado el SurfaceView vacío al primer fragmento que se mostrará, en el índice 0 – detrás de la vista principal. En mi caso, el fragmento de inicio es el fragmento anterior a uno que contiene el fragmento de Google Maps, no estoy seguro de si es importante:

 import android.view.SurfaceHolder; import android.view.SurfaceView; public class HomeFragment extends FragmentBase { private SurfaceView sview; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_home, container, false); //this fixes google maps surface view black screen animation issue sview = new SurfaceView(getActivity()); sview.setZOrderOnTop(true); // necessary SurfaceHolder holder = sview.getHolder(); holder.setFormat(PixelFormat.TRANSPARENT); container.addView(sview, 0); ... } 

Para evitar que el MapView (en realidad es un SurfaceView) creando los agujeros negros, agrego una vista vacía con color de fondo transparente para cubrir todo el MapView, de modo que puede impedir que MapView genere un "agujero" negro. Puede funcionar para su situación.

Tengo el mismo problema con una webview y SlidingMenu y resolví modificando el código fuente de SlidingMenu como se explica aquí por el desarrollador principal.

Comente la aceleración de hardware en el método manageLayers de SlidingMenu. Esta parece ser la única solución ya que SurfaceViews no funciona.

Otra solución alternativa es usar la nueva función GoogleMap.snapshot() , y usar una captura de pantalla del mapa en su lugar; Como se describe aquí .

Tuve la misma cuestión de la pantalla negra en el desplazamiento de la vista de lista, estaba usando el mapa de fragmento con la vista de lista en la misma pantalla que he resuelto este problema con el uso de la propiedad mágica en xml donde estoy hablando ver lista sólo tenemos que poner android: ScrollingCache = "false". Mi problema está resuelto intente esta propiedad para detener el retraso y el parpadeo en sus mapas.

Chicos la mejor solución que encontré fue instanciar su mapa de apoyo a través de este. Hace maravillas

 SupportMapFragment mapFragment = SupportMapFragment.newInstance(new GoogleMapOptions().zOrderOnTop(true)); 

Inténtalo

GetHolder (). SetFormat (PixelFormat.TRANSLUCENT);

Al constructor de SurfaceView. El TextureView también debería funcionar, pero requerirá que deje de soportar los dispositivos secundarios api 14.

Cambie su FrameLayout a RelativeLayout si es posible

Tuve el mismo problema y usé una solución basada en cambiar la "visibilidad".

 private GoogleMap mMap; private SupportMapFragment mMapFragment; mMapFragment = ((SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.mapFragment)); mMap = mMapFragment.getMap(); //Change the visibility to 'INVISIBLE' before the animation to go to another fragment. mMapFragment.getView().setVisibility(View.INVISIBLE); //Change the visibility to 'VISIBLE' after coming back to the original fragment that has map fragment. mMapFragment.getView().setVisibility(View.VISIBLE); 

Esto funcionó para mí … Añadir mapa: zOrderOnTop = "true" a su fragmento como este …

 <fragment android:id="@+id/map" android:layout_width="match_parent" android:layout_height="match_parent" android:name="com.google.android.gms.maps.SupportMapFragment"" map:zOrderOnTop="true"/> 

Recuerde agregar esto a su padre ScrollView

 xmlns:map="http://schemas.android.com/apk/res-auto" 

He aquí una solución muy sencilla que usé para deshacerse del parpadeo en un ViewPager. Me imagino que lo mismo será válido para cualquier fragmento u otro MapView añadido dinámicamente.

El problema realmente no parece ser el propio MapView, sino los recursos necesarios para ejecutar el MapView. Estos recursos solo se cargan la primera vez que inicia un MapView en su actividad y se vuelve a utilizar para cada MapView posterior, como era de esperar. Esta carga de recursos es lo que hace que la pantalla parpadee.

Así que para eliminar el parpadeo, sólo he incluido otro MapView en el diseño de mi actividad (la ubicación en la actividad es irrelevante). Tan pronto como la actividad se ha cargado, sólo establezco la Visibilidad de la MapView extra a GONE. Esto significa que todos los recursos necesarios para su MapView están listos para cuando usted encender cualquiera de sus fragmentos usando MapViews sin retraso, sin parpadear, toda la felicidad.

Esto es, por supuesto, una solución y no una verdadera "solución" al problema subyacente, pero resolverá los efectos secundarios.

Así que para cubrir el código utilizado para la integridad:

Al azar (pero limpio) colocado en mi Layout de la actividad:

 <com.google.android.gms.maps.MapView android:id="@+id/flash_map" android:layout_width="match_parent" android:layout_height="wrap_content" /> 

Entonces en mi clase de actividad

 private MapView flashMap; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Code omitted try { MapsInitializer.initialize(this); } catch (GooglePlayServicesNotAvailableException e) { e.printStackTrace(); } flashMap = (MapView)findViewById(R.id.flash_map); flashMap.onCreate(savedInstanceState); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); flashMap.onSaveInstanceState(outState); } @Override public void onResume() { super.onResume(); flashMap.onResume(); flashMap.setVisibility(View.GONE); // Just like it was never there... } @Override public void onPause() { flashMap.onPause(); super.onPause(); } @Override public void onDestroy() { flashMap.onDestroy(); super.onDestroy(); } @Override public void onLowMemory() { super.onLowMemory(); flashMap.onLowMemory(); } 
  • ¿Cómo puedo obtener las coordenadas de un mapa al toque con MapFragment (no MapView)?
  • java.lang.IllegalStateException: Actividad destruida - fragmento de Android
  • No se puede reemplazar el fragmento dentro de la pestaña por otro fragmento
  • ClassNotFoundException leyendo un objeto Serializable en una clase que extiende MapFragment en onSaveInstanceState
  • Android SupportMapFragment Exception Error
  • Cómo agregar mapfragment dentro de un elemento listview dentro de adaptador?
  • Mapa de MapFragment se carga con lag cuando regrese de otra actividad
  • Rendimiento de varios MapFragments (Android Map API v2)
  • Cómo deshabilitar la función de rotación de mapas en el fragmento de mapa de Android
  • Uso de la funcionalidad mapfragment sin conexión
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.