如何在Android RecyclerView中添加分隔线?


221

我正在开发一个正在使用的android应用程序RecyclerView。我需要添加一个分压器RecyclerView。我试图添加-

recyclerView.addItemDecoration(new
     DividerItemDecoration(getActivity(),
       DividerItemDecoration.VERTICAL_LIST));

以下是我的xml代码-

   <android.support.v7.widget.RecyclerView
    android:id="@+id/drawerList"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="15dp"
    />


要显示不带最后一行的分隔线,请使用
Kishan Solanki

我认为您的代码是正确的。我没看到任何问题。
Rohit Rawat

Answers:


282

在2016年10月更新中,支持库v25.0.0现在具有默认的基本水平和垂直分隔线实现!

https://developer.android.com/reference/android/support/v7/widget/DividerItemDecoration.html

 recyclerView.addItemDecoration(new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL));

3
嗨,谢谢你的信息!有没有办法删除最后一项之后的分隔线?我只是在CardView中实现了列表,底部的cardview分隔线和阴影看起来并不好!
Maxi

4
我遇到了同样的问题,并通过扩展DividerItemDecoration并覆盖getItemOffsets来解决它,然后仅在我不在第一个项目上时才调用super。if(parent.getChildAdapterPosition(view) == state.getItemCount() - 1)然后返回,否则调用超类' getItemOffsets()
罗宾

13
因为我的RecyclerView是垂直的,所以我mLayoutManager.getOrientation()使用了DividerItemDecoration.VERTICAL它并且代替了它,并且起作用了。
亚伦·莱里维耶

2
有没有办法使用这种内置方式来更改分隔线的颜色?
j2emanue

1
@android:attr/listDivider应用程序主题中的@ V.Kalyuzhnyu 如果是颜色资源,则不显示分隔线,我必须使用固定高度的颜色创建可绘制的形状。
A. Ferrand

226

正确的方法是定义ItemDecorationRecyclerView是如下

SimpleDividerItemDecoration.java

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

    public SimpleDividerItemDecoration(Context context) {
        mDivider = context.getResources().getDrawable(R.drawable.line_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);
        }
    }
}

line_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/dark_gray" />

</shape>

最后像这样设置

recyclerView.addItemDecoration(new SimpleDividerItemDecoration(this));

编辑

正如@Alan Solitar指出的

context.getResources().getDrawable(R.drawable.line_divider); 

已贬值,而不是可以使用

ContextCompat.getDrawable(context,R.drawable.line_divider);

3
context.getResources()。getDrawable(R.drawable.line_divider)现在已弃用。
艾伦·S.

2
没问题。这是一个很好的答案,对我来说效果很好。谢谢。
艾伦·S.

3
这对我来说是完美的。但是,我想知道为什么不为该分隔符添加一个简单的<View>到每个单元格的布局中?它的代码少得多。此解决方案是否会降低性能?tx
Greg

4
如果您尝试在物品上滑动或移动,则会出现此实现的问题。
TerNovi

1
@NJ谢谢老兄,您节省了我的时间。
Suhas Bachewar '17

40

如果要同时具有水平和垂直分隔线:

  1. 定义水平和垂直分隔线可绘制对象:

    horizo​​ntal_divider.xml

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android" >
      <size android:height="1dip" />
      <solid android:color="#22000000" />
    </shape>

    vertical_divider.xml

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android" >
        <size android:width="1dip" />
        <solid android:color="#22000000" />
    </shape>
  2. 在下面添加此代码段:

    DividerItemDecoration verticalDecoration = new DividerItemDecoration(recyclerview.getContext(),
            DividerItemDecoration.HORIZONTAL);
    Drawable verticalDivider = ContextCompat.getDrawable(getActivity(), R.drawable.vertical_divider);
    verticalDecoration.setDrawable(verticalDivider);
    recyclerview.addItemDecoration(verticalDecoration);
    
    DividerItemDecoration horizontalDecoration = new DividerItemDecoration(recyclerview.getContext(),
            DividerItemDecoration.VERTICAL);
    Drawable horizontalDivider = ContextCompat.getDrawable(getActivity(), R.drawable.horizontal_divider);
    horizontalDecoration.setDrawable(horizontalDivider);
    recyclerview.addItemDecoration(horizontalDecoration);

有效。但是,如果您更改了horizo​​ntal_divider.xml来划分宽度,并更改了vertical_divider.xml来划分高度,则可以这样创建每个对象DividerItemDecorationverticalDecoration = new DividerItemDecoration(recyclerview.getContext(), DividerItemDecoration.VERTICAL);horizontalDecoration = new DividerItemDecoration(recyclerview.getContext(), DividerItemDecoration.HORIZONTAL);
鲁本·基亚翁

33

所有这些答案使我很接近,但他们每个都缺少关键细节。经过一些研究,我发现最简单的方法是以下三个步骤的组合:

  1. 使用支持库的DividerItemDecoration
  2. 创建具有正确颜色的分隔线
  3. 将此主题中的分隔线设置为listDivider

步骤1:在配置RecyclerView时

recyclerView.addItemDecoration(
        new DividerItemDecoration(context, layoutManager.getOrientation()));

步骤2:在类似res / drawable / divider_gray.xml的文件中

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

步骤3:在应用程式的主题中

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- Other theme items above -->
    <item name="android:listDivider">@drawable/divider_gray</item>
</style>

编辑:更新以跳过最后的分隔线:
使用了一点后,我意识到它正在最后一项之后绘制一个分隔线,这很烦人。因此,我对步骤1进行了如下修改,以覆盖DividerItemDecoration中的默认行为(当然,制作单独的类是另一种选择):

recyclerView.addItemDecoration(
        new DividerItemDecoration(context, layoutManager.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);
                }
            }
        }
);

7
覆盖getItemOffsets似乎对我不起作用。即使我重写并且从不调用超级,分隔线仍会绘制。不知道发生了什么变化。
lostintranslation

2
这对我也不起作用。最后一个分隔线仍在显示。
索蒂

1
最后,我通过复制DividerItemDecoration的源代码创建了自己的分隔器类,并做了一些更改以不绘制最后一个除法器。在绘制方法中,只需忽略最后一个子视图: for (int i = 0; i < childCount; i++) 更改为for (int i = 0; i < childCount - 1; i++)
kientux '18

由于ItemDecoration是在列表项之前绘制的(“在列表项之下”),所以给定的解决方案仅在您的列表项具有100%不透明背景或装饰可绘制对象是100%透明时才起作用(因此用户看到了recyclerView的背景)。否则,无论您在getItemOffsets()中返回什么,分隔线都是可见的
ernazm

31

只需在项目适配器的末尾添加一个View:

<View
 android:layout_width="match_parent"
 android:layout_height="1dp"
 android:background="#FFFFFF"/>

24
使用此解决方案,您还将在列表的末尾得到分隔线。
2016年

5
可以通过在onBindViewHolder中这样说来以编程方式删除最后一行,if(position == getItemCount() - 1) { mDividerView.setVisibility(View.INVISIBLE) }或者必须有其他方法可以这样做。
阿里·卡兹

大多数情况下,最后一行1px高度都看不到
Mehdi Khademloo

@LucasDiego这可以工作,但是我们知道充气很昂贵。
Zohra Khan

21

这是一个简单的自定义分隔线的代码(垂直分隔线/ 1dp height / black):

假设您有支持库:

compile "com.android.support:recyclerview-v7:25.1.1"

Java代码

    DividerItemDecoration divider = new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL);
    divider.setDrawable(ContextCompat.getDrawable(getBaseContext(), R.drawable.my_custom_divider));
    recyclerView.addItemDecoration(divider);

然后是custom_divider.xml文件样本:

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

10

res / drawable文件夹中创建一个单独的xml文件

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

主活动处连接该xml文件(your_file),如下所示:

DividerItemDecoration divider = new DividerItemDecoration(
    recyclerView.getContext(),
    DividerItemDecoration.VERTICAL
);
divider.setDrawable(ContextCompat.getDrawable(getBaseContext(), R.drawable.your_file));
recyclerView.addItemDecoration(divider);

如何添加填充?在形状中使用填充无效。
马卡雷勒

9

Kotlin版本:

recyclerview.addItemDecoration(DividerItemDecoration(this, LinearLayoutManager.VERTICAL))

8

我想你Fragments曾经有RecyclerView

在创建RecyclerViewLayoutManager对象后,只需添加这些行

DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
                DividerItemDecoration.VERTICAL);
        recyclerView.addItemDecoration(dividerItemDecoration);

而已!

它支持水平方向和垂直方向。



7

您需要添加下一行...

mRecyclerView.addItemDecoration(new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL));

7

我处理Divider视图以及Divider插入的方式是通过添加RecyclerView扩展。

1。

通过命名View或RecyclerView添加新的扩展文件:

RecyclerViewExtension.kt

并将setDivider扩展方法添加到RecyclerViewExtension.kt文件中。

/*
* RecyclerViewExtension.kt
* */
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.RecyclerView


fun RecyclerView.setDivider(@DrawableRes drawableRes: Int) {
    val divider = DividerItemDecoration(
        this.context,
        DividerItemDecoration.VERTICAL
    )
    val drawable = ContextCompat.getDrawable(
        this.context,
        drawableRes
    )
    drawable?.let {
        divider.setDrawable(it)
        addItemDecoration(divider)
    }
}

2。

drawable包内部创建一个Drawable资源文件,例如recycler_view_divider.xml

<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:insetLeft="10dp"
    android:insetRight="10dp">

    <shape>
        <size android:height="0.5dp" />
        <solid android:color="@android:color/darker_gray" />
    </shape>

</inset>

在这里你可以指定左,右android:insetLeftandroid:insetRight

3。

在初始化了RecyclerView的Activity或Fragment上,可以通过调用以下命令来设置自定义可绘制对象:

recyclerView.setDivider(R.drawable.recycler_view_divider)

4。

干杯🍺

RecyclerView行与分隔线。


6

因此,这可能不是正确的方法,但我只是将视图添加到了RecyclerView的单项视图中(因为我认为没有内置函数),如下所示:

<View
    android:layout_width="fill_parent"
    android:layout_height="@dimen/activity_divider_line_margin"
    android:layout_alignParentBottom="true"
    android:background="@color/tasklist_menu_dividerline_grey" />

这意味着每个项目的底部都将填充一行。我的#111111背景色高约1dp 。这也给了它一种“ 3D”效果。


2
-这不是办法
Anand Tiwari

5

您可以创建一个简单的可重用分隔符。

创建分隔线:

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; 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>

将分隔器添加到您的Recyclerview:

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

要删除最后一项的分隔线:

为了防止最后一个项目的分隔线绘图,您必须更改此行。

for (int i = 0; i < childCount; i++) 

for (int i = 0; i < childCount-1; i++)

您的最终实现应如下所示:

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 - 1; 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);
        }
    }
}

希望能帮助到你:)


1
这非常有效,我不知道为什么它不是公认的答案
Kennedy Kambo

2

yqritc的RecyclerView-FlexibleDivider使其成为一体。首先将此添加到您的build.gradle

compile 'com.yqritc:recyclerview-flexibledivider:1.4.0' // requires jcenter()

现在,您可以配置和添加一个分频器,在其中设置recyclerView的适配器:

recyclerView.setAdapter(myAdapter);
recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(this).color(Color.RED).sizeResId(R.dimen.divider).marginResId(R.dimen.leftmargin, R.dimen.rightmargin).build());

16
@Gaurav,HorizontalDividerItemDecoration班级在哪里?
iRuth

@iRuth,您需要将Maven库添加到您的.gradle文件中github.com/yqritc/RecyclerView-FlexibleDivider
Hakem Zaied

5
这是一个不完整的答案。也许投反对票是适当的。
周末

值得一提的是,@ gaurav-vachhani
Andrew V.

2

不幸的是,Android只会使小事情变得过于复杂。无需在此处实现DividerItemDecoration即可轻松实现所需的最简单方法:

将RecyclerView的背景色添加到所需的分隔线颜色:

<RecyclerView
    android:id="@+id/rvList"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:divider="@color/colorLightGray"
    android:scrollbars="vertical"
    tools:listitem="@layout/list_item"
    android:background="@android:color/darker_gray"/>

将下边距(android:layout_marginBottom)添加到项目(list_item.xml)的布局根目录:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginBottom="1dp">

    <TextView
        android:id="@+id/tvName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="John Doe" />

    <TextView
        android:id="@+id/tvDescription"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/tvName"
        android:text="Some description blah blah" />

</RelativeLayout>

这应该在项目和RecyclerView的背景颜色之间留出1dp的空间(深灰色将显示为分隔线)。


1

为了使NJ的答案更加简单,您可以执行以下操作:

public class DividerColorItemDecoration extends DividerItemDecoration {

    public DividerColorItemDecoration(Context context, int orientation) {
        super(context, orientation);
        setDrawable(ContextCompat.getDrawable(context, R.drawable.line_divider));
    }
}

1

只需在您的商品底部添加x数量的边距RecycleView Adapter

onCreateViewHolder

LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);

layoutParams.setMargins(0, 0, 0, 5);
itemView.setLayoutParams(layoutParams);

1
recyclerview.addItemDecoration(new DividerItemDecoration(this, 0));

哪里0是水平的,1是Veritical


3
最好使用常量变量,因为该值在支持库的将来版本中可能会发生变化
Irshu,

是的。我们应该使用LinearLayoutManager.HORIZONTAL或LinearLayoutManager.VERTICAL而不是0或1
Freny Christian

0
  class ItemOffsetDecoration(
        context: Context,
        private val paddingLeft: Int,
        private val paddingRight: Int
    ) : RecyclerView.ItemDecoration() {
        private var mDivider: Drawable? = null

        init {
            mDivider = ContextCompat.getDrawable(context, R.drawable.divider_medium)
        }

        override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
            val left = parent.paddingLeft + paddingLeft
            val right = parent.width - parent.paddingRight - paddingRight
            val childCount = parent.childCount
            for (i in 0 until childCount) {
                val child = parent.getChildAt(i)
                val params = child.layoutParams as RecyclerView.LayoutParams
                val top = child.bottom + params.bottomMargin
                val bottom = top + (mDivider?.intrinsicHeight ?: 0)

                mDivider?.let {
                    it.setBounds(left, top, right, bottom)
                    it.draw(c)
                }
            }
        }
    }

您只需要在R.drawable.divider_medium中指定颜色

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

</shape>

并将其添加到您的recyclerView

recyclerView.addItemDecoration(
                        ItemOffsetDecoration(
                            this,
                            resources.getDimension(resources.getDimension(R.dimen.dp_70).roundToInt()).roundToInt(),
                            0
                        )
                    )

参考


0

Bhuvanesh BS解决方案有效。Kotlin版本:

import android.graphics.Canvas
import android.graphics.drawable.Drawable
import androidx.recyclerview.widget.RecyclerView

class DividerItemDecorator(private val mDivider: Drawable?) : RecyclerView.ItemDecoration() {

    override fun onDraw(
        canvas: Canvas,
        parent: RecyclerView,
        state: RecyclerView.State
    ) {

        val dividerLeft = parent.paddingLeft
        val dividerRight = parent.width - parent.paddingRight
        for (i in 0 until parent.childCount - 1) {
            val child = parent.getChildAt(i)
            val dividerTop =
                child.bottom + (child.layoutParams as RecyclerView.LayoutParams).bottomMargin
            val dividerBottom = dividerTop + mDivider!!.intrinsicHeight
            mDivider.setBounds(dividerLeft, dividerTop, dividerRight, dividerBottom)
            mDivider.draw(canvas)
        }
    }
}

0

我认为这是最简单的方法

mDividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
                DividerItemDecoration.VERTICAL);
// or DividerItemDecoration.HORIZONTALL
        mDividerItemDecoration.setDrawable(getDrawable(R.drawable.myshape));
        recyclerView.addItemDecoration(mDividerItemDecoration);

请注意: myshape可以是矩形,要与您要制作分隔线的高度相同

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.