如何使用GridLayoutManager与RecyclerView设置列间距? 在我的布局中设置空白/填充没有效果。


当前回答

这个问题的答案似乎比他们应该做的要复杂。以下是我的看法。

假设您希望网格项之间有1dp的间距。做以下几点:

为每个项目添加0.5dp的填充 给RecycleView添加-0.5dp的填充 就是这样!:)

其他回答

上面的回答已经阐明了设置边缘处理GridLayoutManager和LinearLayoutManager的方法。

但是对于StaggeredGridLayoutManager, Pirdad Sakhizada的回答是:“它可能不太适合StaggeredGridLayoutManager”。应该是关于IndexOfSpan的问题。

您可以通过以下方式获取:

private static class MyItemDecoration extends RecyclerView.ItemDecoration {
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        int index = ((StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams()).getSpanIndex();
    }
}

这个问题的答案似乎比他们应该做的要复杂。以下是我的看法。

假设您希望网格项之间有1dp的间距。做以下几点:

为每个项目添加0.5dp的填充 给RecycleView添加-0.5dp的填充 就是这样!:)

感谢edwardaa的回答https://stackoverflow.com/a/30701422/2227031

另一点需要注意的是:

如果total spacing和total itemWidth不等于屏幕宽度,您还需要调整itemWidth,例如,在适配器onBindViewHolder方法

Utils.init(_mActivity);
int width = 0;
if (includeEdge) {
    width = ScreenUtils.getScreenWidth() - spacing * (spanCount + 1);
} else {
    width = ScreenUtils.getScreenWidth() - spacing * (spanCount - 1);
}
int itemWidth = width / spanCount;

ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) holder.imageViewAvatar.getLayoutParams();
// suppose the width and height are the same
layoutParams.width = itemWidth;
layoutParams.height = itemWidth;
holder.imageViewAvatar.setLayoutParams(layoutParams);

下面的代码工作得很好,每个列都有相同的宽度:

public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {

    private int spanCount;
    private int spacing;
    private boolean includeEdge;

    public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
        this.spanCount = spanCount;
        this.spacing = spacing;
        this.includeEdge = includeEdge;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        int position = parent.getChildAdapterPosition(view); // item position
        int column = position % spanCount; // item column

        if (includeEdge) {
            outRect.left = spacing - column * spacing / spanCount; // spacing - column * ((1f / spanCount) * spacing)
            outRect.right = (column + 1) * spacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing)

            if (position < spanCount) { // top edge
                outRect.top = spacing;
            }
            outRect.bottom = spacing; // item bottom
        } else {
            outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing)
            outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f /    spanCount) * spacing)
            if (position >= spanCount) {
                outRect.top = spacing; // item top
            }
        }
    }
}

使用

1. 没有优势

int spanCount = 3; // 3 columns
int spacing = 50; // 50px
boolean includeEdge = false;
recyclerView.addItemDecoration(new GridSpacingItemDecoration(spanCount, spacing, includeEdge));

2. 与边缘

int spanCount = 3; // 3 columns
int spacing = 50; // 50px
boolean includeEdge = true;
recyclerView.addItemDecoration(new GridSpacingItemDecoration(spanCount, spacing, includeEdge));

如果你有一个在列表和网格之间切换的拨动开关,不要忘记在设置任何新的项目装饰之前调用recyclerView.removeItemDecoration(..)。如果不是这样,那么新的间隔计算将是不正确的。

就像这样:

recyclerView.removeItemDecoration(gridItemDecorator)
recyclerView.removeItemDecoration(listItemDecorator)

if (showAsList) {
    recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
    recyclerView.addItemDecoration(listItemDecorator)
} else {
    recyclerView.layoutManager = GridLayoutManager(this, spanCount)
    recyclerView.addItemDecoration(gridItemDecorator)
}