個人的には、このためにRecyclerViewをサブクラス化したくありません。私にとっては、スパン数を検出するのはGridLayoutManagerの責任であると思われるためです。したがって、RecyclerViewとGridLayoutManagerのAndroidソースコードを掘り下げた後、私は自分のクラス拡張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);
}
}
onLayoutChildrenでスパン数を設定することを選択した理由を実際には覚えていません。このクラスは少し前に作成しました。しかし、重要なのは、ビューが測定された後にそうする必要があるということです。高さと幅を取得できます。
編集1:スパンカウントを正しく設定しない原因となったコードのエラーを修正します。解決策を報告および提案してくれたユーザー@Elyees Aboudaに感謝します。
編集2:いくつかの小さなリファクタリングと手動の方向変更の処理によるエッジケースの修正。報告と解決策を提案してくれたユーザー@tatarizeに感謝します。
LayoutManager
のうちの子どもを産むために仕事やないRecyclerView
の