Personaly Saya tidak suka membuat subkelas RecyclerView untuk ini, karena bagi saya tampaknya ada tanggung jawab GridLayoutManager untuk mendeteksi jumlah rentang. Jadi setelah beberapa kode sumber android menggali untuk RecyclerView dan GridLayoutManager, saya menulis GridLayoutManager perluasan kelas saya sendiri yang melakukan pekerjaan itu:
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);
}
}
Saya sebenarnya tidak ingat mengapa saya memilih untuk mengatur jumlah rentang di onLayoutChildren, saya menulis kelas ini beberapa waktu lalu. Tapi intinya adalah kita harus melakukannya setelah tampilan diukur. jadi kita bisa mendapatkan tinggi dan lebarnya.
EDIT 1: Perbaiki kesalahan dalam kode yang disebabkan oleh pengaturan jumlah rentang yang salah. Terima kasih pengguna @Elyees Abouda untuk melaporkan dan menyarankan solusi .
EDIT 2: Beberapa refactoring kecil dan fix edge case dengan penanganan perubahan orientasi manual. Terima kasih pengguna @tatarize untuk melaporkan dan menyarankan solusi .
LayoutManager
'pekerjaan s untuk meletakkan anak-anak keluar dan tidakRecyclerView
' s