Pessoalmente, não gosto de criar uma subclasse de RecyclerView para isso, porque, para mim, parece que é responsabilidade do GridLayoutManager detectar a contagem de amplitude. Então, depois de pesquisar o código-fonte do Android para RecyclerView e GridLayoutManager, escrevi minha própria classe GridLayoutManager estendida que faz o trabalho:
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);
}
}
Na verdade, não me lembro por que escolhi definir a contagem de amplitude em onLayoutChildren, escrevi esta classe há algum tempo. Mas a questão é que precisamos fazer isso depois que a visualização for medida. para que possamos obter sua altura e largura.
EDIT 1: Corrigir erro no código causado pela configuração incorreta da contagem de amplitude. Obrigado ao usuário @Elyees Abouda por relatar e sugerir soluções .
EDIT 2: Algumas pequenas refatorações e correção de casos extremos com manipulação manual de mudanças de orientação. Obrigado ao usuário @tatarize por relatar e sugerir a solução .
LayoutManager
's trabalho para colocar as crianças para fora e nãoRecyclerView
' s