web-dev-qa-db-ja.com

RecyclerViewは最後のアイテムの後にディバイダー/デコレーターを削除します

私は非常にシンプルなRecyclerViewを持っています。これは私が分周器を設定する方法です

DividerItemDecoration itemDecorator = new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL);
itemDecorator.setDrawable(ContextCompat.getDrawable(getActivity(), R.drawable.news_divider));
recyclerView.addItemDecoration(itemDecorator);

そして、これはdrawable/news_divider.xmlです

<shape xmlns:Android="http://schemas.Android.com/apk/res/Android" Android:shape="rectangle">
    <solid Android:color="@color/white_two"/>
    <size Android:height="1dp"/>
</shape>

問題は、アイテム間で仕切りが作成されただけではない、何らかの愚かな理由です。しかし、最後のアイテムの後も。そして、私はすべてのアイテムの後ではなく、アイテムの間にのみそれが欲しい。

最後のアイテムの後に仕切りが表示されないようにする方法はありますか?

乾杯と感謝

39

このコードを試してください。最後のアイテムの区切り線は表示されません。

public class DividerItemDecorator extends RecyclerView.ItemDecoration {
    private Drawable mDivider;

    public DividerItemDecorator(Drawable divider) {
        mDivider = divider;
    }

    @Override
    public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
        int dividerLeft = parent.getPaddingLeft();
        int dividerRight = parent.getWidth() - parent.getPaddingRight();

        int childCount = parent.getChildCount();
        for (int i = 0; i <= childCount - 2; i++) {
            View child = parent.getChildAt(i);

            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();

            int dividerTop = child.getBottom() + params.bottomMargin;
            int dividerBottom = dividerTop + mDivider.getIntrinsicHeight();

            mDivider.setBounds(dividerLeft, dividerTop, dividerRight, dividerBottom);
            mDivider.draw(canvas);
        }
    }
}

divider.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:shape="rectangle">
    <size
        Android:width="1dp"
        Android:height="1dp" />
    <solid Android:color="@color/grey_300" />
</shape>

Dividerを次のように設定します。

RecyclerView.ItemDecoration dividerItemDecoration = new DividerItemDecorator(ContextCompat.getDrawable(context, R.drawable.divider));
recyclerView.addItemDecoration(dividerItemDecoration);
64
Bhuvanesh BS

提案されているように ここ 次のようにDividerItemDecorationを拡張できます:

recyclerView.addItemDecoration(
    new DividerItemDecoration(context, linearLayoutManager.getOrientation()) {
        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            int position = parent.getChildAdapterPosition(view);
            // hide the divider for the last child
            if (position == parent.getAdapter().getItemCount() - 1) {
                outRect.setEmpty();
            } else {
                super.getItemOffsets(outRect, view, parent, state);
            }
        }
    }
);

[更新]
@ Rebecca Hsiehは次のように指摘しました。

これは、RecyclerViewのアイテムビューに透明な背景がない場合、works、たとえば、

<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:orientation="horizontal"
    Android:background="#ffffff">
    ... 
</LinearLayout>

DividerItemDecoration.getItemOffsetsは、子の位置を測定するためにRecyclerViewによって呼び出されます。このソリューションは、最後のアイテムの後ろに最後の仕切りを配置します。したがって、RecyclerViewのアイテムビューには、最後の仕切りを覆う背景が必要です。これにより、非表示になります。

その他の解決策

仕切りが後ろに描画されないようにする場合は、単純に DividerItemDecoration クラスをコピーまたは拡張し、for (int i = 0; i < childCount; i++)for (int i = 0; i < childCount - 1; i++)に変更して描画動作を変更できます。

37
Maksim Turaev

getItemOffsets()をオーバーライドしないため、受け入れられた回答は装飾用のスペースを割り当てません。

サポートライブラリのDividerItemDecorationを調整して、最後のアイテムから装飾を除外しました

public class DividerItemDecorator extends RecyclerView.ItemDecoration {

    private Drawable mDivider;
    private final Rect mBounds = new Rect();

    public DividerItemDecorator(Drawable divider) {
        mDivider = divider;
    }

    @Override
    public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
        canvas.save();
        final int left;
        final int right;
        if (parent.getClipToPadding()) {
            left = parent.getPaddingLeft();
            right = parent.getWidth() - parent.getPaddingRight();
            canvas.clipRect(left, parent.getPaddingTop(), right,
                    parent.getHeight() - parent.getPaddingBottom());
        } else {
            left = 0;
            right = parent.getWidth();
        }

        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount - 1; i++) {
            final View child = parent.getChildAt(i);
            parent.getDecoratedBoundsWithMargins(child, mBounds);
            final int bottom = mBounds.bottom + Math.round(child.getTranslationY());
            final int top = bottom - mDivider.getIntrinsicHeight();
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(canvas);
        }
        canvas.restore();
    }

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

        if (parent.getChildAdapterPosition(view) == state.getItemCount() - 1) {
            outRect.setEmpty();
        } else
            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
    }
}

デコレータを適用するには、使用します

RecyclerView.ItemDecoration dividerItemDecoration = new DividerItemDecorator(dividerDrawable);
recyclerView.addItemDecoration(dividerItemDecoration);

オリエンテーションを含めるためのソースはここにあります https://Gist.github.com/abdulalin/146f8ca42aa8322692b15663b8d508ff

5
AbdulAli

独自のDividerクラスを作成します( ここの例

仕切りを描画するコードで、リストの最後のアイテムに仕切りを描画するかどうかを最初に確認します。もしそうなら、それを描画しないでください。

OnDrawOverをオーバーライドすると、スクロールバーなどを含むビューの上部に描画されることに注意してください。OnDrawに固執することをお勧めします。 Googleには多くの例がありますが、 this は、独自のデコレータを作成するための優れたチュートリアルです。

2
Kuffs

最後の項目の最終行を削除するDividerDecoratorクラスをアプリで使用します。

public class DividerDecorator extends RecyclerView.ItemDecoration {
    private Drawable mDivider;

    public DividerDecorator(Context context) {
        mDivider = context.getResources().getDrawable(R.drawable.recyclerview_divider);
    }

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        int left = parent.getPaddingLeft();
        int right = parent.getWidth() - parent.getPaddingRight();

        int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = parent.getChildAt(i);

            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();

            int top = child.getBottom() + params.bottomMargin;
            int bottom = top + mDivider.getIntrinsicHeight();

            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }
}

次のコードを使用して、RecyclerViewに設定できます。

mRecyclerViewEvent.addItemDecoration(new DividerDecorator(context));

これがrecyclerview_divider.xmlです

<size
    Android:width="1dp"
    Android:height="1dp" />

<solid Android:color="@color/DividerColor" />
2
savepopulation

これは、最後の項目を無視するAndroidサポートDividerItemDecorationのカスタマイズバージョンです。

https://Gist.github.com/mohsenoid/8ffdfa53f0465533833b0b44257aa641

主な違いは次のとおりです。

private fun drawVertical(canvas: Canvas, parent: RecyclerView) {
    canvas.save()
    val left: Int
    val right: Int

    if (parent.clipToPadding) {
        left = parent.paddingLeft
        right = parent.width - parent.paddingRight
        canvas.clipRect(left, parent.paddingTop, right,
                parent.height - parent.paddingBottom)
    } else {
        left = 0
        right = parent.width
    }

    val childCount = parent.childCount
    for (i in 0 until childCount - 1) {
        val child = parent.getChildAt(i)
        parent.getDecoratedBoundsWithMargins(child, mBounds)
        val bottom = mBounds.bottom + Math.round(child.translationY)
        val top = bottom - mDivider!!.intrinsicHeight
        mDivider!!.setBounds(left, top, right, bottom)
        mDivider!!.draw(canvas)
    }
    canvas.restore()
}

private fun drawHorizontal(canvas: Canvas, parent: RecyclerView) {
    canvas.save()
    val top: Int
    val bottom: Int

    if (parent.clipToPadding) {
        top = parent.paddingTop
        bottom = parent.height - parent.paddingBottom
        canvas.clipRect(parent.paddingLeft, top,
                parent.width - parent.paddingRight, bottom)
    } else {
        top = 0
        bottom = parent.height
    }

    val childCount = parent.childCount
    for (i in 0 until childCount - 1) {
        val child = parent.getChildAt(i)
        parent.layoutManager.getDecoratedBoundsWithMargins(child, mBounds)
        val right = mBounds.right + Math.round(child.translationX)
        val left = right - mDivider!!.intrinsicWidth
        mDivider!!.setBounds(left, top, right, bottom)
        mDivider!!.draw(canvas)
    }
    canvas.restore()
}
1