使用带有StaggeredGridLayoutManager的RecyclerView时,如何避免项目之间的双重空间?

时间:2015-03-07 09:11:15

标签: android android-recyclerview margins staggeredgridlayout

我使用RecyclerView和StaggeredGridLayoutManager制作一个两列列表。但是如何在左列和右列之间设置右边距。我已经使用此代码从顶部创建右边距,但如何解决列之间的双倍空格。

public class SpacesItemDecoration extends RecyclerView.ItemDecoration {
    private int space;

    public SpacesItemDecoration(int space) {
        this.space = space;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        outRect.left = space;
        outRect.right = space;
        outRect.bottom = space;

        // Add top margin only for the first or second item to avoid double space between items
        // Add top margin only for the first or second item to avoid double space between items
        if((parent.getChildCount() > 0 && parent.getChildPosition(view) == 0)
            || (parent.getChildCount() > 1 && parent.getChildPosition(view) == 1))
        outRect.top = space;
}

在活动中:

recyclerView.addItemDecoration(new SpacesItemDecoration(20));

我尝试使用view.getX(),它总是返回0.

任何人都可以帮助我吗?非常感谢!

8 个答案:

答案 0 :(得分:7)

在您的情况下,您可以将两个边距设置为RecyclerView。但在我的情况下,在RecyclerView中有一个与屏幕宽度匹配的图像,我使用ItemDecoration来解决问题。

setup.py develop

答案 1 :(得分:4)

public class EqualGapItemDecoration extends RecyclerView.ItemDecoration {

    private int spanCount;
    private int spacing;

    public EqualGapItemDecoration(int spanCount, int spacing) {
        this.spanCount = spanCount;
        this.spacing = spacing;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {

        StaggeredGridLayoutManager.LayoutParams layoutParams = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();

        if (layoutParams.isFullSpan()) {
            outRect.set(0, 0, 0, 0);
        } else {
            int spanIndex = layoutParams.getSpanIndex();
            int layoutPosition = layoutParams.getViewLayoutPosition();
            int itemCount = parent.getAdapter().getItemCount();

            boolean leftEdge = spanIndex == 0;
            boolean rightEdge = spanIndex == (spanCount - 1);

            boolean topEdge = spanIndex < spanCount;
            boolean bottomEdge = layoutPosition >= (itemCount - spanCount);

            int halfSpacing = spacing / 2;

            outRect.set(
                    leftEdge ? spacing : halfSpacing,
                    topEdge ? spacing : halfSpacing,
                    rightEdge ? spacing : halfSpacing,
                    bottomEdge ? spacing : 0
            );
        }
    }
}

答案 2 :(得分:3)

我通过设置项目边距和RecyclerView填充来解决这个问题。边距和填充都是预期空间的一半,因此问题消失了。

答案 3 :(得分:0)

我会略微更改并修改相对问题的答案

public class SpacesItemDecoration extends RecyclerView.ItemDecoration {
    private final int mSpace;

    public SpacesItemDecoration(int space) {
        this.mSpace = space;
    }

    @Override
    public void getItemOffsets(Rect outRect, final View view, final RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        int position = parent.getChildAdapterPosition(view);
        int spanIndex = ((StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams()).getSpanIndex();
        if (spanIndex == 0) {
            outRect.left = 30;
            outRect.right = 15;
        } else {//if you just have 2 span . Or you can use (staggeredGridLayoutManager.getSpanCount()-1) as last span
            outRect.left = 15;
            outRect.right = 30;
        }
        outRect.bottom = 30;
        // Add top margin only for the first item to avoid double space between items
        if (parent.getChildAdapterPosition(view) == 0) {
            outRect.top = 30;
            outRect.right = 30;
        }
    }
}

答案 4 :(得分:0)

根据spanindex在ItemDecoration中设置不同的左/右空间仅适用于具有固定大小的项目视图。 如果项目视图包含高度的图像视图集wrap_content,则项目视图可能会更改跨度位置,但跨度索引未按您的意愿更新,边距将是一团糟。

我的方式是,使用对称的左/右空间作为视图项目。

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    // init
    recyclerView = (RecyclerView) rv.findViewById(R.id.img_waterfall);
    layoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setAdapter(new MyAdapter(getContext()));
    recyclerView.addItemDecoration(new SpacesItemDecoration(
        getResources().getDimensionPixelSize(R.dimen.space)));
}


private static class SpacesItemDecoration extends RecyclerView.ItemDecoration {
    private final int space;
    public SpacesItemDecoration(int space) {
        this.space = space;
    }
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
                               RecyclerView.State state) {
        outRect.bottom = 2 * space;
        int pos = parent.getChildAdapterPosition(view);
        outRect.left = space;
        outRect.right = space;
        if (pos < 2)
            outRect.top = 2 * space;
    }
}

然后为RecylerView设置相同的填充(左/右) 机器人:paddingLeft = “@扪/空间” 机器人:paddingRight = “@扪/空间”

    <android.support.v7.widget.RecyclerView
        android:id="@+id/img_waterfall"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingLeft="@dimen/space"
        android:paddingRight="@dimen/space"/>

答案 5 :(得分:0)

可以在RecyclerView的两侧设置填充:

myRecyclerView.setPadding(10,0,10,0);

通过这种方式,您可以均衡侧面和列之间的空间。

答案 6 :(得分:0)

我通过以下三个步骤解决了这个问题:

  1. 将marginStart和marginEnd添加到具有相同值的父项(RecyclerView)
<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginStart="@dimen/margin_small"
    android:layout_marginEnd="@dimen/margin_small"
    app:layoutManager="androidx.recyclerview.widget.StaggeredGridLayoutManager"
    app:spanCount="2" />
  1. 创建一个自定义ItemDecorator类,并扩展RecyclerView.ItemDecoratior。获取父代父母,然后根据情况修改每个孩子一半的内部边距
class SpaceItemDecorator : RecyclerView.ItemDecoration() {

    override fun getItemOffsets(
        outRect: Rect,
        view: View,
        parent: RecyclerView,
        state: RecyclerView.State
    ) {
        super.getItemOffsets(outRect, view, parent, state)

        val layoutParams = view.layoutParams as StaggeredGridLayoutManager.LayoutParams
        val spanIndex = layoutParams.spanIndex

        if (spanIndex == 0) {
            val marginParentEnd = parent.marginEnd
            layoutParams.marginEnd = marginParentEnd / 2
        } else {
            val marginParentStart = parent.marginStart
            layoutParams.marginStart = marginParentStart / 2
        }

        view.layoutParams = layoutParams
    }
}
  1. 将自定义ItemDecorator添加到recyclerView
recyclerview.addItemDecoration(SpaceItemDecorator())

仅此而已,没有边界/填充硬编码,并且使用Koltin xD

注意:重要的是不要在孩子的视图布局中建立任何水平边距

答案 7 :(得分:0)

以下代码可以毫无问题地处理StaggeredGridLayout(至少从我的经验来看)。您只需要给SpaceItemDecorator留空格即可。

class SpaceItemDecoration(private val spacing: Int) :
    RecyclerView.ItemDecoration() {

    override fun getItemOffsets(
        outRect: Rect,
        view: View,
        parent: RecyclerView,
        state: RecyclerView.State
    ) {

        val lm = parent.layoutManager as StaggeredGridLayoutManager
        val lp = view.layoutParams as StaggeredGridLayoutManager.LayoutParams

        val spanCount = lm.spanCount
        val spanIndex = lp.spanIndex
        val positionLayout = lp.viewLayoutPosition
        val itemCount = lm.itemCount
        val position = parent.getChildAdapterPosition(view)

        outRect.right = spacing / 2
        outRect.left = spacing / 2
        outRect.top = spacing / 2
        outRect.bottom = spacing / 2

        if (spanIndex == 0) outRect.left = spacing

        if (position < spanCount) outRect.top = spacing

        if (spanIndex == (spanCount - 1)) outRect.right = spacing

        if (positionLayout > (itemCount - spanCount)) outRect.bottom = spacing
    }
}

您可以像这样获得像素间距:

 val spacingInPixels = resources.getDimensionPixelSize(R.dimen.grid_layout_margin)

然后,您只需要将物品装饰分配给回收者视图:

recycler_view.addItemDecoration(
                  SpaceItemDecoration(
                        spacingInPixels
                    )
                )