android - studio - ViewPager no vuelve a dibujar el contenido, permanece/se vuelve en blanco
view pager adapter android studio (11)
Finalmente logramos encontrar una solución. Aparentemente nuestra implementación sufrió de dos problemas:
- nuestro adaptador no eliminó la vista en
destroyItem()
. - estábamos almacenando vistas en caché para que tuviéramos que inflar nuestro diseño una sola vez y, dado que no estábamos eliminando la vista en
destroyItem()
, no lo íbamos a agregar eninstantiateItem()
sino que simplemente devolvíamos la vista en caché correspondiente a la actual posición.
No he examinado demasiado profundamente el código fuente de ViewPager
, y no es exactamente explícito que tengas que hacerlo, pero el documento dice:
destroyItem ()
Eliminar una página para la posición dada. El adaptador es responsable de eliminar la vista de su contenedor, aunque solo debe asegurarse de que esto se haga para el momento en que regrese de finishUpdate (ViewGroup).
y:
Un PagerAdapter muy simple puede optar por utilizar las Vistas de página como objetos clave, devolviéndolas de instanciastemáticas (ViewGroup, int) después de la creación y agregarlas al Grupo de Vista padre. Una implementación correspondiente de destroyItem (ViewGroup, int, Object) eliminaría View del parent ViewGroup y isViewFromObject (View, Object) podría implementarse como return view == object ;.
Así que mi conclusión es que ViewPager
basa en su adaptador subyacente para agregar / eliminar explícitamente sus elementos destroyItem()
/ destroyItem()
. Es decir, si su adaptador es una subclase de PagerAdapter
, su subclase debe implementar esta lógica.
Nota al ViewPager
: tenga en cuenta this si usa listas dentro de ViewPager
.
Estamos sufriendo un problema muy extraño con ViewPager aquí. Insertamos listas en cada página de ViewPager y activamos notifyDataSetChanged tanto en el adaptador de lista como en el adaptador de buscapersonas cuando actualizamos los datos de la lista.
Lo que observamos es que, a veces, la página no actualiza su árbol de vista, es decir, permanece en blanco, o incluso desaparece cuando lo busca. Cuando se busca y retrocede varias veces, el contenido reaparecerá repentinamente. Parece que a Android le falta una actualización de vista aquí. También noté que al depurar con el visor de jerarquía, al seleccionar una vista siempre volverá a aparecer, aparentemente porque el visor de jerarquía fuerza a la vista seleccionada a redibujarse.
Sin embargo, no pude hacer este trabajo programáticamente; invalidar la vista de lista, o incluso el buscapersonas completo, no tuvo ningún efecto.
Esto es con la biblioteca de compatibilidad-v4_r7. También traté de usar la última revisión, ya que afirma solucionar muchos problemas relacionados con la visualización de buscapersonas, pero empeoró las cosas (por ejemplo, los gestos se rompieron, por lo que a veces no me dejaba pasar página por todas las páginas).
¿Alguien más se está metiendo en estos problemas, también, o tienes una idea de qué podría estar causando esto?
La Biblioteca de soporte de Android tiene una Actividad de demostración que incluye una ViewPager con un ListView en cada página. Probablemente deberías echarle un vistazo y ver qué hace.
En Eclipse (con Android Dev Tools r20):
- Seleccione
New > Android Sample Project
- Seleccione su nivel de API objetivo (sugiero el más nuevo disponible)
- Seleccione
Support4Demos
- Haga clic con el botón derecho en el proyecto y seleccione
Android Tools > Add Support Library
- Ejecuta la aplicación y selecciona
Fragment
y luegoPager
El código para esto está en src/com.example.android.supportv4.app/FragmentPagerSupport.java
. ¡Buena suerte!
Me encontré con este mismo problema al usar un ViewPager y FragmentStatePagerAdapter. Intenté usar un controlador con un retraso de 3 segundos para llamar a invalidate () y requestLayout () pero no funcionó. Lo que funcionó fue restablecer el color de fondo de viewPager de la siguiente manera:
MyFragment.java
private Handler mHandler;
private Runnable mBugUpdater;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = new ViewPager(getActivity());
//...Create your adapter and set it here...
mHandler = new Handler();
mBugUpdater = new Runnable(){
@Override
public void run() {
mVp.setBackgroundColor(mItem.getBackgroundColor());
mHandler = null;
mBugUpdater = null;
}
};
mHandler.postDelayed(mBugUpdater,50);
return rootView;
}
@Override
public void onPause() {
if(mHandler != null){
//Remove the callback if it hasn''t triggered yet
mHandler.removeCallbacks(mBugUpdater);
mHandler = null;
mBugUpdater = null;
}
super.onPause();
}
Me encontré con esto y tuve problemas muy similares. Incluso lo pedí en desbordamiento de pila.
Para mí, en el padre del padre de mi vista, alguien LinearLayout
y anuló requestLayout()
sin llamar a super.requestLayout()
. Esto impidió que onMeasure
y onLayout
se llamaran en mi ViewPager (aunque hierarchyviewer los llama manualmente). Sin ser medidos aparecerán en blanco en ViewPager.
Así que revisa tus vistas que contienen. Asegúrese de que subclasifiquen desde View y no anulen ciegamente requestLayout ni nada similar.
Para mí, el problema volvía a la actividad después de que se matara el proceso de la aplicación. Estoy usando un adaptador de paginador de vista personalizado modificado a partir de las fuentes de Android. El paginador de vista está incrustado directamente en la actividad.
Llamar a viewPager.setCurrentItem(position, true);
(con animación) después de configurar los datos y notifyDataSetChanged () parece funcionar, pero si el parámetro se establece en falso no lo hace y el fragmento queda en blanco. Este es un caso extremo que puede ser de ayuda para alguien.
Si ViewPager
se establece dentro de un Fragment con FragmentPagerAdapter
, use getChildFragmentManager()
lugar de getSupportFragmentManager()
como el parámetro para inicializar su FragmentPagerAdapter
.
mAdapter = new MyFragmentPagerAdapter(getChildFragmentManager());
En lugar de
mAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager());
Tuve el mismo problema, que tiene algo que ver con ListView
(porque mi vista vacía aparece bien si la lista está vacía). Acabo de llamar a requestLayout()
en el problemático ListView
. ¡Ahora está bien!
Tuve exactamente el mismo problema, pero en realidad destruí la vista en destroyItem (pensé). Sin embargo, el problema fue que lo destruí usando viewPager.removeViewAt(index);
viewPager.removeView((View) object);
de viewPager.removeView((View) object);
Incorrecto:
@Override
public void destroyItem(ViewGroup viewPager, int position, Object object) {
viewPager.removeViewAt(position);
}
Derecha:
@Override
public void destroyItem(ViewGroup viewPager, int position, Object object) {
viewPager.removeView((View) object);
}
Tuve un problema con los mismos síntomas, pero una causa diferente que resultó ser un error tonto de mi parte. Pensé que lo agregaría aquí en caso de que ayude a alguien.
Tenía un ViewPager usando FragmentStatePagerAdapter que solía tener dos fragmentos, pero luego agregué un tercero. Sin embargo, olvidé que el límite predeterminado de la página fuera de pantalla es 1, así que cuando cambie al tercer fragmento nuevo, el primero se destruye y luego se vuelve a crear después de volver. El problema era que mi actividad estaba a cargo de notificar estos fragmentos para inicializar su estado de UI. Esto pasó a funcionar cuando los ciclos de vida de actividad y fragmentación eran los mismos, pero para solucionarlo tuve que cambiar los fragmentos para inicializar su propia IU durante el ciclo de vida de inicio. Al final, también terminé cambiando setOffscreenPageLimit a 2 para que los tres fragmentos se mantuvieran vivos en todo momento (seguro en este caso ya que no consumían mucha memoria).
Tuve un problema similar. ViewPager
en caché las vistas porque solo necesito 3 vistas en ViewPager
. Cuando me adelanto todo está bien, pero cuando empiezo a deslizar hacia atrás aparece un error, dice que "mi vista ya tiene un padre". La solución es eliminar elementos innecesarios de forma manual.
@Override
public Object instantiateItem(ViewGroup container, int position) {
int localPos = position % SIZE;
TouchImageView view;
if (touchImageViews[localPos] != null) {
view = touchImageViews[localPos];
} else {
view = new TouchImageView(container.getContext());
view.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
touchImageViews[localPos] = view;
}
view.setImageDrawable(mDataModel.getPhoto(position));
Log.i(IRViewPagerAdpt.class.toString(), "Add view " + view.toString() + " at pos: " + position + " " + localPos);
if (view.getParent() == null) {
((ViewPager) container).addView(view);
}
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object view) {
// ((ViewPager) container).removeView((View) view);
Log.i(IRViewPagerAdpt.class.toString(), "remove view " + view.toString() + " at pos: " + position);
}
..................
private static final int SIZE = 3;
private TouchImageView[] touchImageViews = new TouchImageView[SIZE];
ViewPager intenta hacer cosas inteligentes en torno a la reutilización de elementos, pero requiere que devuelva nuevas posiciones cuando las cosas hayan cambiado. Intente agregar esto a su PagerAdapter:
public int getItemPosition (Object object) { return POSITION_NONE; }
Básicamente le dice a ViewPager que todo ha cambiado (y lo obliga a volver a crear instancias de todo). Es lo único que se me ocurre en la cabeza.