19

我使用 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。

谁能帮我?非常感谢!

4

9 回答 9

10

以下代码将处理 StaggeredGridLayoutManager、GridLayoutManager 和 LinearLayoutManager。

public class SpacesItemDecoration extends RecyclerView.ItemDecoration {

    private int halfSpace;

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

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

        if (parent.getPaddingLeft() != halfSpace) {
            parent.setPadding(halfSpace, halfSpace, halfSpace, halfSpace);
            parent.setClipToPadding(false);
        }

        outRect.top = halfSpace;
        outRect.bottom = halfSpace;
        outRect.left = halfSpace;
        outRect.right = halfSpace;
    }
}
于 2015-08-24T19:35:31.697 回答
8

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

  class ViewItemDecoration extends RecyclerView.ItemDecoration {

    public ViewItemDecoration() {
    }

    @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();
        int type = adapter.getItemViewType(position);
        switch(type){
          case YOUR_ITEMS:
                if (spanIndex == 0) {
                    outRect.left = 10;
                    outRect.right = 5;
                } else {//if you just have 2 span . Or you can use (staggeredGridLayoutManager.getSpanCount()-1) as last span
                    outRect.left = 5;
                    outRect.right = 10;
                }
        }
    }

}
于 2015-09-10T02:21:53.173 回答
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
            );
        }
    }
}
于 2017-04-28T02:23:55.087 回答
3

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

于 2015-03-08T07:42:46.120 回答
0

可以在 RecyclerView 的两侧设置 padding:

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

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

于 2018-07-06T17:22:08.047 回答
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;
        }
    }
}
于 2016-01-19T09:41:59.137 回答
0

根据 spanindex 在 ItemDecoration 中设置不同的左/右空间仅适用于具有固定大小的项目视图。如果 item view 包含 image view set wrap_content in height,item view 可能会改变 span 位置,但是 span index 没有按照你的意愿更新,margin 会很乱。

我的方式是,使用对称的左/右空间来查看项目。

@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(left/right) 设置相同的填充 android:paddingLeft="@dimen/space" android:paddingRight="@dimen/space"

    <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"/>
于 2016-05-05T11:59:26.123 回答
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。获取marigns parent,然后根据情况修改每个child一半的内部边距
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

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

于 2020-02-12T04:03:37.980 回答
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
                    )
                )
于 2020-03-28T16:14:17.253 回答