Personnellement, je n'aime pas sous-classer RecyclerView pour cela, car pour moi, il semble que GridLayoutManager ait la responsabilité de détecter le nombre de plages. Donc, après quelques recherches de code source Android pour RecyclerView et GridLayoutManager, j'ai écrit ma propre classe étendue GridLayoutManager qui fait le travail:
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);
}
}
Je ne me souviens pas vraiment pourquoi j'ai choisi de définir le nombre de span dans onLayoutChildren, j'ai écrit ce cours il y a quelque temps. Mais le fait est que nous devons le faire après avoir mesuré la vue. afin que nous puissions obtenir sa hauteur et sa largeur.
EDIT 1: Correction d'une erreur dans le code causée par un réglage incorrect du nombre de plages. Merci à l'utilisateur @Elyees Abouda d' avoir signalé et suggéré une solution .
EDIT 2: Quelques petits refactoring et cas de bord fixe avec gestion manuelle des changements d'orientation. Merci à l'utilisateur @tatarize d' avoir signalé et suggéré une solution .
LayoutManager
travail de mettre les enfants dehors et pasRecyclerView
de