Центр Горизонтальная последняя строка с использованием диапазона Recycler GridLayoutManager

Я пытаюсь сделать элементы последнего горизонтального ряда строк в виде ресайклеров. Я использую GridLayoutManager для достижения функциональности. Используя setSpanSizeLookup, я хочу отрегулировать размер диапазона для последней строки, как указано сообщениями на SO, но, к сожалению, я не могу отслеживать, какая строка в данный момент заполняется, поэтому моя логика не работает.

Чего я хочу достичь:

введите описание изображения здесь

код:

static private int NUM_OF_COLUMNS = 3;

final GridLayoutManager manager = new GridLayoutManager(getBaseActivity(), NUM_OF_COLUMNS);

        manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {

            int rowNum = 0;

            @Override
            public int getSpanSize(int position) {

                int spanSize = 1;

                if(position == 0)
                    rowNum = 0; //reset it

                //check if it is last row
                int numOfRows = (int) Math.ceil((double) list.size() / NUM_OF_COLUMNS);
                if(rowNum == numOfRows - 1) {
                    //get num of items in last row
                    int items = list.size() - (NUM_OF_COLUMNS * rowNum);
                    if(items == 1)
                        spanSize = 3;
                }

                if(rowNum % NUM_OF_COLUMNS == 0) //if last element
                    rowNum++;

                return spanSize;
            }
        });

        recyclerView.setLayoutManager(manager);

Выше кода управляет номером строки, так как я не знаю, как получить текущую позицию строки и столбца для сетки. Может ли кто-нибудь указать на правильное направление? Спасибо.

Ответ 1

Посмотрите на это. Это библиотека Google, которая предоставляет аналогичные возможности CSS Flexible Box Layout Module для Android.

в деятельности

  FlexboxLayoutManager layoutManager = new FlexboxLayoutManager();
        layoutManager.setFlexWrap(FlexWrap.WRAP);
        layoutManager.setFlexDirection(FlexDirection.ROW);
        layoutManager.setAlignItems(AlignItems.CENTER);
        viewDecks.setLayoutManager(layoutManager);

в Adapter.ViewHolder

ViewGroup.LayoutParams lp = itemView.getLayoutParams();
            if (lp instanceof FlexboxLayoutManager.LayoutParams) {
                FlexboxLayoutManager.LayoutParams flexboxLp = (FlexboxLayoutManager.LayoutParams) lp;
                flexboxLp.setFlexGrow(1.0f);
                flexboxLp.setAlignSelf(AlignSelf.CENTER);
            }

и убедитесь, что вы установили android:layout_gravity="center"

Ответ 2

Я полагаю, с известным количеством элементов в адаптере, можно написать с простым расширением для класса GridLayoutManager.

Мне просто нужно было это, так что вот рабочее решение...

/**
 * Get grid layout manager with special optimization for span of the last row.
 * In case, last row won't have same number of items as previous rows, its content
 * will be spread over whole row.
 *
 * @param ctx current context
 * @param spanCount number of items per row
 * @param itemsCount number of items in adapter
 * @param orientation manager orientation
 * @param reverseLayout flag for orientation direction
 */
fun getGridManagerLastRowCenter(ctx: Context, spanCount: Int, itemsCount: Int,
        @RecyclerView.Orientation orientation :Int, reverseLayout: Boolean)
        : GridLayoutManager {

    // get number of items in last row
    val lastRowCount = itemsCount % spanCount
    if (lastRowCount == 0) {
        return GridLayoutManager(ctx, spanCount, orientation, reverseLayout)
    }

    // number of rows with all items
    val fullRows = itemsCount / spanCount
    // "span" counter for whole row (as minimum divider)
    val rowSpan = spanCount * lastRowCount
    // span value for item in the first rows
    val baseRowItemSpan = rowSpan / spanCount
    // span value for item in the last row
    val lastRowItemSpan = rowSpan / lastRowCount

    // return generated manager
    return GridLayoutManager(ctx, rowSpan, orientation, reverseLayout).apply {
        spanSizeLookup = object: GridLayoutManager.SpanSizeLookup() {

            override fun getSpanSize(position: Int): Int {
                return if (position / spanCount < fullRows) {
                    baseRowItemSpan
                } else {
                    lastRowItemSpan
                }
            }
        }
    }
}

Использование с помощью простого вызова

rv.layoutManager = UtilsListAco.getGridManagerLastRowCenter( ctx, 3, items.size, RecyclerView.VERTICAL, false)