Лично аз не обичам да подкласифицирам RecyclerView за това, защото за мен изглежда, че има отговорност на GridLayoutManager да открие броя на обхватите. Така че след известно копаене на изходния код на Android за RecyclerView и GridLayoutManager написах моя собствен разширен клас GridLayoutManager, който върши работата:
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);
}
}
Всъщност не помня защо избрах да задам span count в onLayoutChildren, написах този клас преди известно време. Но въпросът е, че трябва да го направим, след като видимостта бъде измерена. така че можем да получим неговата височина и ширина.
РЕДАКТИРАНЕ 1: Коригиране на грешка в кода, причинена от неправилно задаване на броя на диапазоните. Благодарим на потребителя @Elyees Abouda за докладването и предложенията решение.
РЕДАКТИРАНЕ 2: Малко преработване и корекция на краен случай с ръчна обработка на промените в ориентацията. Благодарим на потребителя @tatarize за докладването и предложенията решение.
person
s.maks
schedule
15.05.2015