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:
- Cómo crear una interfaz de usuario como la aplicación Inbox de Google en Android
- Obtener encabezados de sección para trabajar con SuperSLiM y RecyclerView
- AppBarLayout no siempre vuelve a entrar en desplazamiento hacia abajo
- Cómo agregar una vista dinámica entre los elementos de RecyclerView en android?
- Cómo guardar la posición de desplazamiento de RecyclerView con RecyclerView.State?
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í:
Si vuelvo a desplazarte hacia arriba, y luego desplácese hacia abajo de nuevo, las imágenes aparecen exactamente donde deberían estar:
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>
- Diseño como la aplicación HotStar
- ¿Recyclerview hace que el último elemento agregado sea el elemento seleccionado?
- Lista 2D con RecyclerView en HorizontalScrollView
- Hace notificydatasetchanged llamada onCreateViewHolder al usar RecyclerView
- Android: Cómo implementar una galería de imágenes con RecyclerView
- Recycler View Adapter con EditText
- RecyclerView no se desplaza hacia abajo
- RecyclerView: obtenga todas las vistas / presentaciones existentes
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á
- Función User.getUserId () en el punto final de nube api devuelve null para un objeto de usuario que no es nulo
- AccountManager no agrega una cuenta personalizada en la vista previa de Android N