Search code examples
androidandroid-recyclerviewgridlayoutmanager

GridLayoutManager on a wrapped layout does not size up the RecyclerView to display the items


RecyclerView with wrap_content and GridLayoutManager does not display the items. It doesn't enlarge to make room for the items.

First of all, I noticed there is an issue (74772) open for it, but it isn't solved yet as of December 2015, and not until “early 2016”.

Someone appeared to have made this CustomGridLayoutManager, also available on Github, but it still doesn't seem to make enough room for all items, making the RecyclerView appear cropped (but scrollable) even when there is enough room for the RecyclerView in its parent.

Any ideas as to how to make the RecyclerView properly size up the items and show it without scrolling, when that is possible?


Solution

  • That class seems to take into account, when measuring, only the first child and the first child of each row (whichever dimension is assigned depends on the orientation). See this (comments by me):

    if (getOrientation() == HORIZONTAL) {
        if (i % getSpanCount() == 0) { // only for first child of row.
            width = width + mMeasuredDimension[0];
        }
        if (i == 0) { // only for first item.
            height = mMeasuredDimension[1];
        }
    }
    

    Something identical happens to orientation VERTICAL (catched in the else that follows).

    In order to account for my needs, I measured each child, checking the largest child in each row, then applying the maximum constraints to the row. When each row was finished measured, then the row size was added to the overall size that was needed.

    if (getOrientation() == VERTICAL) {
        rowMeasure[1] = Math.max(rowMeasure[1], childMeasure[1]);
        rowMeasure[0] += childMeasure[0];
    } else {
        rowMeasure[0] = Math.max(rowMeasure[0], childMeasure[0]);
        rowMeasure[1] += childMeasure[1];
    }
    
    // When finishing the row (last item of row), adds the row dimensions to the view.
    if (i % getSpanCount() == getSpanCount() - 1 || i == state.getItemCount() - 1) {
        rowsSized[addIndex] += rowMeasure[addIndex];
        rowsSized[maxIndex] = Math.max(rowsSized[maxIndex], rowMeasure[maxIndex]);
        rowMeasure[addIndex] = 0;
        rowMeasure[maxIndex] = 0;
    }
    

    The full class is available at the end of this answer. The above shows only the logic.

    I did not fully tested this solution yet, as I bumped into this issue this week, and tried to solve it—again, at least for my needs—yesterday (dec 08).

    You can check how I tackled this problem with my WrappedGridLayoutManager here.

    As stated in the issue comments, you must pay attention to the RecyclerView's State, using its getItemCount() instead. I also recommend taking a look at getViewForPosition(int) to see if/how this may be affected by prelayouts conditions and so on.