android - proyecto - Mover MapFragment(SurfaceView) hace parpadear el fondo negro
proyecto google maps android (17)
No es posible tomar una captura de pantalla de un mapa, pero tal vez alguien se inspire en esto.
Es posible con la interfaz de instantáneas de GoogleMap . Ahora puede mostrar una instantánea del mapa mientras se desplaza por la página. Con esto resolví mi problema con ViewPager, quizás puedas cambiar el código para que se ajuste a tu SlidingMenu.
Aquí está mi código para establecer 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 (haz que match_parent).
Y aquí estoy controlando el pergamino:
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 mapa (FragmentMap) está en la posición 1, así que necesito controlar el desplazamiento desde la posición 0 a 1 y desde la posición 1 a 2 (la primera cláusula if). "getRegisteredFragment ()" es una función en mi FragmentPagerAdapter personalizado, en el que tengo un SparseArray (Fragment) llamado "registeredFragments".
Entonces, cada vez que te desplazas hacia o desde tu mapa, siempre ves una instantánea de él. Este trabajo es muy bueno para mi.
Estoy tratando de implementar la nueva API de Android Google Maps (v2). Sin embargo, no parece ir bien con SlidingMenu . Como ya sabrá, la implementación de MapFragment
se basa en SurfaceView
. El problema es que a SurfaceView
no le gusta moverlo, es decir, colocarlo en vistas movibles:
-
ViewPager
, -
ScrollView
, -
ListView
, - o el ya mencionado
SlidingMenu
.
Cuando lo mueves, deja un agujero negro en el lugar donde se colocaron sus píxeles originalmente. Se ve algo como this .
Este problema se puede resolver parcialmente especificando un fondo transparente en el SurfaceView
o incluso colocando una View
transparente sobre él. Simplemente no puedo entender si solo para mí los resultados son inaceptables, o si tengo un problema diferente que hace que se vea como se ve.
Para ver cómo se ve, mira ESTE VIDEO .
(Lo siento por la calidad, pero el problema se puede ver fácilmente de todos modos)
Cuando se saca una vista de lista normal (la pantalla naranja) mientras se abre SlidingMenu
, la animación es suave y agradable. Pero tan pronto como aparece MapFragment
, hay un extraño problema de actualización / parpadeo / sincronización en el mapa.
Probado en HTC One S y Samsung Galaxy ACE.
Mi idea súper-loca de resolverlo: cada vez que se inicia la animación de apertura, toma una captura de pantalla de MapFragment
(debería ser posible con SurfaceView) y colócala durante la duración de la animación.Pero realmente no sé cómo hacerlo ... No es posible tomar una captura de pantalla de un mapa , pero tal vez alguien se inspire en esto.
O tal vez deshabilite volver a dibujar el mapa de otra forma, no lo sé.
ACTUALIZAR:
Encontrado this
Parece que SurfaceView se puede cambiar a TextureView para eliminar esas limitaciones. Pero dado que MapFragment se basa en SurfaceView, no sé si se puede lograr.
Otra actualización Parece que este problema se ha resuelto en los dispositivos 4.1+. Acaban de usar TextureView. pero en las versiones más bajas todavía tenemos que usar soluciones temporales.
Aquí hay una solución muy simple que utilicé para eliminar el flasheo en un ViewPager. Me imagino que lo mismo sucederá con cualquier Fragmento u otro MapView agregado dinámicamente.
El problema no parece ser realmente el MapView en sí, sino los recursos necesarios para ejecutar MapView. Estos recursos solo se cargan la primera vez que inicia un MapView en su actividad y se reutiliza para cada MapView posterior, como era de esperar. Esta carga de recursos es lo que hace que la pantalla parpadee.
Entonces, para eliminar el flasheo, acabo de incluir otro MapView en el diseño de mi Actividad (la ubicación en la actividad es irrelevante). Tan pronto como la Actividad se haya cargado, simplemente configuro la Visibilidad de la Vista de mapa adicional en GONE. Esto significa que todos los recursos necesarios para su MapView están listos para cuando active cualquiera de sus Fragmentos usando MapViews sin retraso, sin flasheo, toda la felicidad.
Esto es, por supuesto, una solución alternativa y no una ''solución'' real al problema subyacente, pero resolverá los efectos secundarios.
Entonces, para cubrir el código utilizado para la integridad:
Al azar (pero limpiamente) colocado en mi diseño de actividad:
<com.google.android.gms.maps.MapView
android:id="@+id/flash_map"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Luego 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();
}
Bueno, citando a Dianne Hackborn (una ingeniera de Android)
La vista de la superficie es en realidad DETRÁS de su ventana, y un agujero en la ventana para que pueda verlo. De este modo, puede colocar las cosas encima en su ventana, pero nada en su ventana puede aparecer detrás de ella. Publicación original
Esta arquitectura es parte de por qué ves estos parpadeos.
Algunos parpadeos a veces aparecen debido a doble búfer: el blog de codificación de Android explica más .
También puede probar y subclasificar el SurfaceView
para intentar dibujar el fondo de forma diferente. No he visto un ejemplo de esto que no cambie el índice z para que sea el de la parte superior. Mira esta publicación SO
De lo contrario, te recomiendo obtener SurfaceHolder
después de SurfaceHolder
tu vista (intenta hacer una vista temporal hasta entonces) y eliminar SurfaceView
mientras no SurfaceView
enfocado y en la pantalla.
Cambie su FrameLayout a RelativeDistribuya si es posible
Chicos, la mejor solución que encontré fue crear una instancia de su mapa de soporte a través de esto. Hace maravillas
SupportMapFragment mapFragment = SupportMapFragment.newInstance(new GoogleMapOptions().zOrderOnTop(true));
En mi caso, tenía un Fragmento inicial, que con un clic de botón intercambiaba un segundo fragmento con un MapFragment dentro de él. Me di cuenta de que este parpadeo solo ocurría la primera vez que intercambiaba el fragmento, haciendo estallar la pila posterior, y el intercambio en otro fragmento del mismo tipo no causaba un parpadeo.
Entonces, pensando que tenía algo que ver con agregar un SurfaceView inicial a la ventana, traté de agregar una instancia vacía de SurfaceView a mi fragmento inicialmente cargado, detrás de su vista principal. Y bingo, ¡no parpadees más cuando animas en el próximo fragmento!
Sé que no es la solución más limpia, pero funciona. El MapFragment de Google (o SupportMapFragment en mi caso) todavía funciona bien, ya que el SurfaceView no utilizado se encuentra en el fragmento anterior.
Debo agregar que estoy usando la API v2.
Actualizar @VenomVendor
Agrego 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 si eso importa:
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);
...
}
Esta es una idea loca, no mueva MapView ;-)
Es decir, crea un ancho de pantalla completa de MapView detrás de tu aplicación en FrameLayout. A continuación, coloque sus vistas en la parte superior y haga un agujero en MapView en la posición que necesita para mostrarlo. Cuando se mueva, deberá actualizar la posición del mapa para mantenerse sincronizado, de modo que el usuario siga viendo la misma sección del mapa, pero debería actualizarse mejor que mover una vista de superficie.
Esto funcionó para mí ... Agregar mapa: zOrderOnTop = "true" a tu 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 ScrollView principal
xmlns:map="http://schemas.android.com/apk/res-auto"
Otra solución alternativa es usar la nueva función GoogleMap.snapshot()
y usar una captura de pantalla del mapa; como se describe here .
Para evitar que MapView (en realidad es un SurfaceView) cree los agujeros negros, agrego una vista vacía con un color de fondo transparente para cubrir todo el MapView, de modo que pueda evitar que MapView genere un "agujero" negro. Puede funcionar para su situación.
Por supuesto, la solución adecuada será que Google solucione el problema (consulte la edición 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 nuevos (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 estén centradas cuando se seleccionan.
Actualización: este problema fue resuelto por Google el 28 de agosto, pero supongo que aún tiene que ser lanzado en una versión.
Puedes usar esta biblioteca
https://github.com/NyxDigital/NiceSupportMapFragment/
Esto funciona bien para mi.
Tengo el mismo problema con una vista web y SlidingMenu y yo lo solucionamos modificando el código fuente de SlidingMenu tal como lo explica 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.
Tuve el mismo problema de pantalla negra al desplazarme de la vista de lista, estaba usando un fragmento de mapa con vista de lista en la misma pantalla, he resuelto este problema con el uso de la propiedad mágica en xml, donde estoy hablando de lista, solo tenemos que poner android: scrollingCache = "false". Mi problema está solucionado. Prueba esta propiedad para detener el retraso y el parpadeo en tus mapas.
Tuve el mismo problema y usé una solución alternativa 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);
agrega android:hardwareAccelerated="true"
en tu archivo de manifiesto.
Ejemplo: <application android:name=".Sample" android:hardwareAccelerated="true" />
intenta agregar ...
getHolder (). setFormat (PixelFormat.TRANSLUCENT);
al constructor de SurfaceView. El TextureView también debería funcionar, pero requerirá que retire soporte para dispositivos sub api 14.