RecyclerView – elementos de pantalla que saltan el primer pase de diseño

Tengo problemas con uno de mis adaptadores. Tengo una selección de imágenes que se muestran en una cuadrícula como la siguiente:

Introduzca aquí la descripción de la imagen

Esto funciona bien cuando tengo una sola pantalla de valor de los elementos y todos ellos aparecen muy bien. El problema aparece cuando hay más elementos para desplazarse hacia abajo. Inicialmente, cuando GridLayout hacia abajo los elementos aparecen en blanco, los contenedores GridLayout están allí y el código para mostrar las imágenes se ejecuta, pero no aparecen en la pantalla como se muestra aquí:

El problema

Si vuelvo a desplazarte hacia arriba, y luego desplácese hacia abajo de nuevo, las imágenes aparecen exactamente donde deberían estar:

Introduzca aquí la descripción de la imagen

Parece que necesito actualizar el diseño o decirle al renderizador que algo ha cambiado, pero nada de lo que intento parece hacer nada. He intentado llamar a requestLayout e invalidate pero no parece resolver el problema. También registré un GlobalOnLayoutListener, pero eso no fue mejor.

Aquí está el código relevante:

Esto es de mi método onBindViewHolder

 final GridLayout grid = ((KKAlbumViewHolder) holder).mGridLayout; grid.removeAllViews(); int width = grid.getWidth(); if(width > 0) { albumHolder.setPreviewImages(posts); }else { albumHolder.itemView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { albumHolder.itemView.removeOnLayoutChangeListener(this); albumHolder.setPreviewImages(posts); albumHolder.mGridLayout.invalidate(); } }); } 

Este es el método que uso para el diseño de las imágenes. Básicamente establece las imágenes en una cuadrícula irregular, por lo que si hay una imagen larga o alta, esa imagen intentará tomar una fila completa o una columna completa dependiendo de qué espacio es libre. La razón por la que configuro el parámetro width y height es tan picasso no se queja del método .fit() :

 public void setPreviewImages(ArrayList<KKPost> posts) { Picasso picasso = Picasso.with(itemView.getContext()); int space = 0; int tl = 1 << 0; int tr = 1 << 1; int bl = 1 << 2; int br = 1 << 3; int lCol = tl | bl; int rCol = tr | br; int tRow = tl | tr; int bRow = bl | br; int full = lCol | rCol; boolean hasLongImage = false; for(KKPost post : posts) { if(space == full){ break; } int margin = 2; ImageView view = new ImageView(itemView.getContext()); GridLayout.LayoutParams param = new GridLayout.LayoutParams(); view.setBackgroundColor(Color.LTGRAY); if(posts.size() < 4){ param.columnSpec = GridLayout.spec(0, 2); param.rowSpec = GridLayout.spec(0, 2); param.width = mGridLayout.getWidth(); param.height = mGridLayout.getHeight(); mGridLayout.addView(view, param); picasso.load(post.url).fit().centerCrop().into(view); break; } if (post.aspectRatio >= 1.2 && !hasLongImage) { //landscape if((space & tRow) == 0){ param.rowSpec = GridLayout.spec(0, 1); param.columnSpec = GridLayout.spec(0, 2); param.height = mGridLayout.getHeight()/2; param.width = mGridLayout.getWidth(); param.bottomMargin = margin; space |= tRow; mGridLayout.addView(view, param); picasso.load(post.url).fit().centerCrop().into(view); hasLongImage = true; continue; } if((space & bRow) == 0){ param.rowSpec = GridLayout.spec(1, 1); param.columnSpec = GridLayout.spec(0, 2); param.height = mGridLayout.getHeight()/2; param.width = mGridLayout.getWidth(); param.topMargin = margin; space |= bRow; mGridLayout.addView(view, param); picasso.load(post.url).fit().centerCrop().into(view); hasLongImage = true; continue; } } else if (post.aspectRatio <= 0.8 && post.aspectRatio > 0 && !hasLongImage) { //portrait if((space & lCol) == 0){ param.columnSpec = GridLayout.spec(0, 1); param.rowSpec = GridLayout.spec(0, 2); param.height = mGridLayout.getHeight(); param.width = mGridLayout.getWidth()/2; param.rightMargin = margin; space |= lCol; mGridLayout.addView(view, param); picasso.load(post.url).fit().centerCrop().into(view); hasLongImage = true; continue; } if((space & rCol) == 0){ param.columnSpec = GridLayout.spec(1, 1); param.rowSpec = GridLayout.spec(0, 2); param.height = mGridLayout.getHeight(); param.width = mGridLayout.getWidth()/2; param.leftMargin = margin; space |= rCol; mGridLayout.addView(view, param); picasso.load(post.url).fit().centerCrop().into(view); hasLongImage = true; continue; } } //square or no space or unknown if((space & tl) == 0){ param.columnSpec = GridLayout.spec(0,1); param.rowSpec = GridLayout.spec(0,1); space |= tl; param.bottomMargin = margin; param.rightMargin = margin; }else if((space & tr) == 0) { param.columnSpec = GridLayout.spec(1,1); param.rowSpec = GridLayout.spec(0,1); space |= tr; param.bottomMargin = margin; param.leftMargin = margin; }else if((space & bl) == 0){ param.columnSpec = GridLayout.spec(0,1); param.rowSpec = GridLayout.spec(1,1); space |= bl; param.rightMargin = margin; param.topMargin = margin; }else if((space & br) == 0){ param.columnSpec = GridLayout.spec(1,1); param.rowSpec = GridLayout.spec(1,1); space |= br; param.leftMargin = margin; param.topMargin = margin; } param.height = mGridLayout.getHeight()/2; param.width = mGridLayout.getWidth()/2; mGridLayout.addView(view, param); picasso.load(post.url).fit().centerCrop().into(view); } } } 

¿Por qué esto parece saltarse hacia fuera en el primer pase de la representación para los artículos no visibles inicialmente?

EDIT: Hice un poco de refactorización para poder reutilizar imágenes en lugar de eliminar / crear nuevas y han descubierto que las vistas que se agregan para los elementos no obtener una devolución de llamada onLayoutChange. Todos los demás elementos reciben la devolución de llamada onLayoutChange y, como antes, los elementos que no reciben la llamada inicialmente, la obtengan después de desplazarme hacia arriba y desplazarse hacia abajo de nuevo. Ver:

 view.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { view.removeOnLayoutChangeListener(this); picasso.load(post.url).into(view); } }); 

Edición: 15 de noviembre

Aquí está el xml para el diseño del visualizador

 <?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.CardView android:id="@+id/album_card_view" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:card_view="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" card_view:cardCornerRadius="@dimen/feed_card_corner_radius" card_view:cardElevation="@dimen/cardview_default_elevation" card_view:cardMaxElevation="@dimen/cardview_default_elevation" card_view:cardUseCompatPadding="true" xmlns:autofit="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <android.support.percent.PercentRelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/percent_layout"> <GridLayout android:background="@color/white" android:id="@+id/preview_grid_layout" android:columnCount="2" android:rowCount="2" android:alignmentMode="alignBounds" android:layout_height="0dp" android:layout_width="0dp" app:layout_widthPercent="100%" app:layout_aspectRatio="100%"> </GridLayout> </android.support.percent.PercentRelativeLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="@dimen/card_padding_4dp" android:orientation="vertical"> <TextView android:id="@+id/album_title" android:layout_width="match_parent" android:layout_height="wrap_content" tools:text="Family Photos"/> </LinearLayout> </LinearLayout> </android.support.v7.widget.CardView> 

Como usted está tratando de hacer una lista tal vez debería considerar el uso de la clase RecyclerView . De esta manera usted podrá utilizar el LayoutManager para diseñar sus imágenes más fácilmente. Esto podría ser mejor como su disposición no es una rejilla estándar (que tiene columnas constantes anchos y alturas). Un ejemplo interesante para buscar un LayoutManager personalizado se puede encontrar aquí .

Dado que el código completo no está allí para que pueda hacer una conjetura. Parece que al desplazarse por primera vez, el adaptador de reciclaje crea las vistas antes de que la red tenga la oportunidad de crear y agregar vistas. Supongo que si utiliza otro adaptador, es decir, el adaptador de red para rellenar sus vistas de cuadrícula, debería funcionar bien.

Estoy saltando que está utilizando onScrollListener para su vista de reciclador para detectar el desplazamiento y luego cargar más cuadrículas que a su vez cargar más elementos de la rejilla a través de adaptador de rejilla para cada rejilla.

Compruebe si tiene setHasStableIds(true) , si lo hace que tiene que sobrescribir getItemId(int position) para especificar ids para cada views.If no hacer eso Las onBindViewholders() posteriores onBindViewholders() no se activará y su vista no se actualizará

  • ANDROID: Múltiples vistas de tarjeta dentro de la vista de reciclador
  • El adaptador de RecyclerView notifyDataSetChanged no funciona
  • Cómo utilizar RecyclerView.scrollToPosition () para mover la posición a la parte superior de la vista actual?
  • Diferenciar entre una acción de Drag y una acción de Fling en recyclerview
  • Agregar los efectos de un RippleDrawable y un StateListDrawable a un RecyclerView
  • LayoutManager para RecyclerView Grid con diferente ancho de celda
  • FindFirstVisibleItemPositions no funciona para recycleview android
  • ¿Cómo puedo eliminar OnClickListeners de ViewHolders de RecyclerView cuando se eliminan?
  • Pasar los datos de los elementos de los clics hechos por RecyclerView CardView a la actividad
  • ¿Que es mejor? NotifyDataSetChanged o notifyItemChanged en el bucle?
  • El más correctamente para guardar el estado de RecyclerView?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.