After I made a RecyclerView grid with a header, I realized that I want to make it auto fit as well. I want to define the size of each item and let the system compute the spanCount
automatically.
To determine the number of spans, I need two things: the width of the RecyclerView
, and the width of each item.
AutofitRecyclerView
We extend RecyclerView
to get access to its width. As for the width of each item,
when GridView
has android:numColumns="auto_fit"
, it uses android:columnWidth
to compute the number of columns. Let's reuse that attribute.
private void init(Context context, AttributeSet attrs) { if (attrs != null) { int[] attrsArray = { android.R.attr.columnWidth }; TypedArray array = context.obtainStyledAttributes( attrs, attrsArray); columnWidth = array.getDimensionPixelSize(0, -1); array.recycle(); } manager = new GridLayoutManager(getContext(), 1); setLayoutManager(manager); }
In the constructor, we read the value of android:columnWidth
and save it in a member variable.
Later in onMeasure
will will use it to determine the span count.
Even though we will be setting the span count in onMeasure
, the app will crash if we wait until then to define a GridLayoutManager
, so we create one here as well, with a span count of 1.
In onMeasure
, we ask the super class to perform the measurement, then take the value from getMeasuredWidth
to compute the span count.
protected void onMeasure(int widthSpec, int heightSpec) { super.onMeasure(widthSpec, heightSpec); if (columnWidth > 0) { int spanCount = Math.max(1, getMeasuredWidth() / columnWidth); manager.setSpanCount(spanCount); } }
Notice the Math.max
call? This makes sure that we will have at least a span count of 1, even if the column width is defined to be larger than the width of the RecyclerView
.
With that, the span count changes with the width of the RecyclerView
.
One thing to note: we are using the column width the compute the span count, and once that is given to the RecyclerView
it will turn around and compute the width of each item. So for instance if your RecyclerView
is 320dp
wide and you use a column width of 72dp
, a span count of 4
(320dp / 72dp = 4.4444
) will be given to the RecyclerView
, which will make your items 320dp / 4 = 80dp
wide, not 72dp
. Make sure your item layout takes that into account.
Source: https://github.com/chiuki/android-recyclerview
Why bother?
Since GridView
already supports auto fit, why bother reimplementing it using RecyclerView
? RecyclerView
has a lot of other functionalities like built-in animations for inserting and removing items, reordering etc, so you may want to use that instead of GridView
.