Personalmente, no me gusta subclasificar RecyclerView para esto, porque para mí parece que GridLayoutManager tiene la responsabilidad de detectar el recuento de intervalos. Entonces, después de investigar un poco el código fuente de Android para RecyclerView y GridLayoutManager, escribí mi propia clase GridLayoutManager extendida que hace el trabajo:
public class GridAutofitLayoutManager extends GridLayoutManager
{
private int columnWidth;
private boolean isColumnWidthChanged = true;
private int lastWidth;
private int lastHeight;
public GridAutofitLayoutManager(@NonNull final Context context, final int columnWidth) {
/* Initially set spanCount to 1, will be changed automatically later. */
super(context, 1);
setColumnWidth(checkedColumnWidth(context, columnWidth));
}
public GridAutofitLayoutManager(
@NonNull final Context context,
final int columnWidth,
final int orientation,
final boolean reverseLayout) {
/* Initially set spanCount to 1, will be changed automatically later. */
super(context, 1, orientation, reverseLayout);
setColumnWidth(checkedColumnWidth(context, columnWidth));
}
private int checkedColumnWidth(@NonNull final Context context, final int columnWidth) {
if (columnWidth <= 0) {
/* Set default columnWidth value (48dp here). It is better to move this constant
to static constant on top, but we need context to convert it to dp, so can't really
do so. */
columnWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48,
context.getResources().getDisplayMetrics());
}
return columnWidth;
}
public void setColumnWidth(final int newColumnWidth) {
if (newColumnWidth > 0 && newColumnWidth != columnWidth) {
columnWidth = newColumnWidth;
isColumnWidthChanged = true;
}
}
@Override
public void onLayoutChildren(@NonNull final RecyclerView.Recycler recycler, @NonNull final RecyclerView.State state) {
final int width = getWidth();
final int height = getHeight();
if (columnWidth > 0 && width > 0 && height > 0 && (isColumnWidthChanged || lastWidth != width || lastHeight != height)) {
final int totalSpace;
if (getOrientation() == VERTICAL) {
totalSpace = width - getPaddingRight() - getPaddingLeft();
} else {
totalSpace = height - getPaddingTop() - getPaddingBottom();
}
final int spanCount = Math.max(1, totalSpace / columnWidth);
setSpanCount(spanCount);
isColumnWidthChanged = false;
}
lastWidth = width;
lastHeight = height;
super.onLayoutChildren(recycler, state);
}
}
En realidad, no recuerdo por qué elegí establecer el recuento de intervalos en onLayoutChildren, escribí esta clase hace algún tiempo. Pero el punto es que debemos hacerlo después de medir la vista. para que podamos obtener su altura y ancho.
EDITAR 1: Soluciona el error en el código causado por configurar incorrectamente el recuento de intervalos. Gracias al usuario @Elyees Abouda por informar y sugerir una solución .
EDITAR 2: Algunas pequeñas refactorizaciones y arreglos de bordes con manejo manual de cambios de orientación. Gracias usuario @tatarize por informar y sugerir una solución .
LayoutManager
trabajo de los niños es dejar a los niños y noRecyclerView
's