web-dev-qa-db-ja.com

StaggeredGridLayoutManagerでRecyclerViewを使用するときに、アイテム間の二重スペースを回避するにはどうすればよいですか?

StaggeredGridLayoutManagerでRecyclerViewを使用して、2列のリストを作成しています。しかし、左の列と右の列の間に右マージンを設定する方法。私はこのコードを使用して上から右マージンを作成しましたが、列間の二重スペースを解決する方法。

_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を返します。

誰か助けてもらえますか?どうもありがとう!

15
outofmemory

次のコードは、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;
    }
}
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;
                }
        }
    }

}
7
Antikvo
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
            );
        }
    }
}
4
Donny

アイテムのマージンとRecyclerViewのパディングを設定することで自分で解決しました。マージンとパディングの両方が予想されるスペースの半分であるため、問題は解消されました。

3
outofmemory

RecyclerViewの両側にパディングを設定することができます。

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

このようにして、側面と列の間のスペースを均等化できます。

0
Tyg

次のコードは、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
                    )
                )
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(左/右)に同じパディングを設定します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"/>
0
emotionfxxk

相対的な質問の両方の回答を少し変更して変更します

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;
        }
    }
}
0
Hardy

私はこれを次の方法で3つのステップで解決しました。

  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())

マージン/パディングハードコードなしで、KoltinxDではこれですべてです

注:子のビューレイアウトに水平方向のマージンを設定しないことが重要です

0
Gabriel Perez