为RecyclerView创建可变的列大小布局管理器 [英] Creating a variable column size layout manager for RecyclerView

查看:69
本文介绍了为RecyclerView创建可变的列大小布局管理器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个布局管理器,将其子级水平放置,直到遇到回收者视图的宽度为止.如果到达边缘,则应在下一行中布置子代.

例如,假设在回收者视图中有4个项目-item1item2item3item4. item1item2的视图彼此相邻放置.还剩下一些空间.但是item3's视图无法适应该宽度.因此,item3转到下一行.但是现在剩下的差距应该在item1item2之间平均分配.

I am trying to create a layout manager that would lay it's children horizontally until it encounters the width of the recycler view. If it reaches the edge, it should layout the children in the next row.

For example suppose there are 4 items in the recycler view - item1, item2, item3 and item4. View's of item1 and item2 are being laid out next to each other. There is still some space left. But item3's view cannot fit into that width. So item3 goes to the next line. But the gap that was left should now be equally divided between item1 and item2.

| <item1><item2><--gap-->|
|<-----item3---->        |

这应该变成

| <--item1--> <--item2-->|
|<-----item3---->        |

,并且如果item4's视图适合item3之后的空间,则应将其放置在该位置.

and if item4's view fits within the space after item3, it should be laid out there.

| <--item1--> <--item2--> |
|<-----item3----><-item4->|


通过GridLayoutManagerStaggeredGridLayoutManager无法实现此目的,因为它们没有考虑单个项目的宽度变化.

要编写自定义布局管理器,我有一种感觉,我应该重写布局管理器的onLayoutChildren方法.但是我有点卡住了.我不确定该怎么做.任何帮助,将不胜感激. 谢谢.


This couldn't be achieved through GridLayoutManager or StaggeredGridLayoutManager because they don't account for varying width of individual items.

To write a custom layout manager, I have a feeling that I should override onLayoutChildren method of layout manager. But I am a bit stuck at this point. I am not sure how to go about this. Any help would be appreciated. Thanks.

推荐答案

我也遇到过类似的问题,但是使用GridLayout解决了这个问题.应该从一开始就创建所有视图的缺点:

I've had similar issue, but solved this using GridLayout. The minuses that all views should be created from the start:

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:app="http://schemas.android.com/apk/res-auto"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

        <android.support.v7.widget.GridLayout
            android:id="@+id/bubble_grid"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:scrollbars="vertical"
            android:scrollbarStyle="outsideOverlay"
            android:layout_gravity="top|left"
            app:orientation="vertical"
            app:columnCount="@integer/grid_cells">
        </android.support.v7.widget.GridLayout>

    </ScrollView>

这是一个适配器:

public class GridAdapter {
    /**
     * Indicates maximum filled row in current column, column is the index of arr, row is the value
     * [224444555550000000]
     * It equals to:
     * [***********-------]
     * [***********-------]
     * [--*********-------]
     * [--*********-------]
     * [------*****-------]
     * [------------------]
     */
    private final int[] mRowMatrix;

    public GridAdapter(GridLayout gridLayout) {
        mGridLayout = gridLayout;
        mPlacedList = new ArrayList<>(10);
        mUnplacedList = new LinkedList<>();

        mNumColumns = ResHelper.getInteger(R.integer.grid_cells);
        mMinCells = ResHelper.getInteger(R.integer.min_cells);
        mMaxCells = ResHelper.getInteger(R.integer.max_cells);
        mRowMatrix = new int[mNumColumns];
    }

    public void notifyDataSetChanged() {

        while (mUnplacedList.size() > 0) {
            final int toCol = findColWithMinRow();
            final int gapSize = findGapSizeForCol(toCol);
            final CustomView view = findAppropriate(gapSize);
            if (view == null) {
                final int filledRow = toCol > 0
                        ? (toCol + gapSize < mRowMatrix.length ? Math.min(mRowMatrix[toCol - 1], mRowMatrix[toCol + gapSize]) : mRowMatrix[toCol - 1])
                        : mRowMatrix[gapSize];
                for (int j = toCol, jCount = toCol + gapSize; j < jCount; j++) {
                    mRowMatrix[j] = filledRow;
                }
            } else {
                placeView(view, toCol, mRowMatrix[toCol]);
            }
        }
    }

    /**
     * Put view in certain column and row in the gridlayout
     */
    private void placeView(CustomView view, int toCol, int toRow) {
        final int gridSize = view.getGridSize();
        final GridLayout.LayoutParams params = new GridLayout.LayoutParams();
        params.width = params.height = gridSize * mCellSize;
        params.columnSpec = GridLayout.spec(toCol, gridSize);
        params.rowSpec = GridLayout.spec(toRow, gridSize);

        mPlacedList.add(view);
        mUnplacedList.remove(view);
        mGridLayout.addView(view, params);

        final int filledRow = toRow + gridSize;
        for (int j = toCol, count = toCol + gridSize; j < count; j++) {
            mRowMap[j] = filledRow;
        }
    }

    /**
     * Find empty gap which starts from toCol
     * [*********************]
     * [******------*****----] here col = 6, size = 3
     * [******------*****----]
     * [******------*****----]
     * [*****************----]
     * @param toCol
     * @return
     */
    private int findGapSizeForCol(int toCol) {
        final int fromRow = mRowMatrix[toCol];
        int i = toCol;
        for (; i < mNumColumns; i++) {
            if (fromRow != mRowMatrix[i]) {
                break;
            }
        }
        return i - toCol;
    }

    /**
     * Find column with minimum filled row
     * [*********************]
     * [*****************----] here col = 17
     * [******------*****----]
     * [******------*****----]
     * @return
     */
    private int findColWithMinRow() {
        int minRow = Integer.MAX_VALUE, minCol = 0;
        for (int i = 0, count = mRowMatrix.length; i < count; i++) {
            if (minRow > mRowMatrix[i]) {
                minRow = mRowMatrix[i];
                minCol = i;
            }
        }
        return minCol;
    }

    /**
     * Find customView with appropriate size for the empty gap
     */
    private CustomView findAppropriate(int size) {
        for (int j = mUnplacedList.size() - 1; j >= 0; j--) {
            if (mUnplacedList.get(j).getGridSize() <= size) {
                return mUnplacedList.get(j);
            }
        }
        return null;
    }

}

这篇关于为RecyclerView创建可变的列大小布局管理器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆