¿Cómo se puede agregar una línea divisoria en un RecyclerView de Android?

221

Estoy desarrollando una aplicación de Android donde la estoy usando RecyclerView. Necesito agregar un divisor de RecyclerView. Traté de agregar

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

a continuación está mi código xml -

   <android.support.v7.widget.RecyclerView
    android:id="@+id/drawerList"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="15dp"
    />
sofquestion 8
fuente
3
Supongo que esto lo ayudará a stackoverflow.com/q/24618829/942224
Sanket Kachhela
Para mostrar el divisor sin la última línea, use esto
Kishan Solanki
Creo que tu código es correcto. No veo ningun problema
Rohit Rawat

Respuestas:

282

En la actualización de octubre de 2016, la biblioteca de soporte v25.0.0 ahora tiene una implementación predeterminada de divisores horizontales y verticales básicos disponibles.

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

 recyclerView.addItemDecoration(new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL));
Aditya Vyas-Lakhan
fuente
3
¡Hola, gracias por la información! ¿Hay alguna forma de eliminar el divisor después del último elemento? ¡Solo tengo un CardView donde se implementa la Lista y el divisor + sombra de cardview en la parte inferior no se ve bien!
Maxi
44
Tuve el mismo problema y lo resolví extendiendo DividerItemDecoration y anulando getItemOffsets, luego solo llamé a super si no estoy en el primer elemento. if(parent.getChildAdapterPosition(view) == state.getItemCount() - 1)luego regrese, de lo contrario llame a la superclase ' getItemOffsets().
Robin
13
En lugar de mLayoutManager.getOrientation(), lo usé DividerItemDecoration.VERTICALy funcionó, ya que mi RecyclerView es vertical.
Aaron Lelevier
2
¿Hay alguna manera de cambiar el color del divisor usando esta forma integrada?
j2emanue
1
@ V.Kalyuzhnyu @android:attr/listDivideren el tema de la aplicación no muestra un divisor si es un recurso de color, tuve que crear una forma dibujable con mi color con una altura fija.
A. Ferrand
226

La forma correcta es definir ItemDecorationpara el RecyclerViewes el siguiente

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>

Finalmente configúrelo así

recyclerView.addItemDecoration(new SimpleDividerItemDecoration(this));

Editar

Como señaló @Alan Solitar

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

se deprecia en lugar de eso puedes usar

ContextCompat.getDrawable(context,R.drawable.line_divider);
Nueva Jersey
fuente
3
context.getResources (). getDrawable (R.drawable.line_divider) ahora está en desuso.
Alan S.
2
No hay problema. Esta es una buena respuesta y funcionó perfectamente para mí. Gracias.
Alan S.
3
Esto funciona perfectamente de mi lado. Sin embargo, me pregunto por qué no agregar un <View> simple para este separador en el diseño de cada celda. Es mucho menos código. ¿Es esta solución menos buena en cuanto a rendimiento? tx
Greg
44
El problema con esta implementación surge si intenta deslizar o mover elementos.
TerNovi
1
@NJ Gracias amigo, me has ahorrado tiempo.
Suhas Bachewar
40

Si desea tener divisores horizontales y verticales:

  1. Definir elementos de dibujo divisores horizontales y verticales:

    horizontal_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. Agregue este segmento de código a continuación:

    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);
Mohammed Mukhtar
fuente
Funcionó. Pero si cambia horizontal_divider.xml para dividir el ancho y vertical_divider.xml para dividir la altura, podría crear cada uno DividerItemDecorationasí: verticalDecoration = new DividerItemDecoration(recyclerview.getContext(), DividerItemDecoration.VERTICAL);y horizontalDecoration = new DividerItemDecoration(recyclerview.getContext(), DividerItemDecoration.HORIZONTAL);.
Ruben O. Chiavone
33

Todas estas respuestas me acercaron, pero a cada una le faltaba un detalle clave. Después de un poco de investigación, encontré que la ruta más fácil es una combinación de estos 3 pasos:

  1. Utilice la biblioteca de soporte DividerItemDecoration
  2. Crea un divisor con el color correcto
  3. Establezca este divisor en su tema como listDivider

Paso 1: mientras configura RecyclerView

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

Paso 2: en un archivo como 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>

Paso 3: en el tema de la aplicación

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

EDITAR: actualizado para omitir el último divisor:
después de usar esto un poco, me di cuenta de que estaba dibujando un divisor después del último elemento, lo que era molesto. Así que modifiqué el Paso 1 de la siguiente manera para anular ese comportamiento predeterminado en DividerItemDecoration (por supuesto, hacer una clase separada es otra opción):

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);
                }
            }
        }
);
gMale
fuente
77
Anular getItemOffsets no parece funcionar para mí. Incluso si anulo y nunca llamo super, el divisor todavía está dibujado. No estoy seguro de qué cambió.
lostintranslation
2
A mí tampoco me funciona. El último divisor sigue apareciendo.
Sotti
1
Terminé creando mi propia clase de divisor copiando la fuente de DividerItemDecoration, y cambié un poco para no dibujar el último divisor. En el método de dibujo, simplemente ignore la última vista secundaria: for (int i = 0; i < childCount; i++) cambie afor (int i = 0; i < childCount - 1; i++)
kientux
Dado que ItemDecoration se dibuja antes del elemento de la lista ("debajo" del elemento de la lista), la solución dada funciona solo si el elemento de la lista tiene un fondo 100% opaco, o cuando la decoración dibujable es 100% transparente (para que el usuario vea el fondo de recyclerView). De lo contrario, el divisor es visible sin importar lo que devuelva en getItemOffsets ()
ernazm
31

Simplemente agregue una Vista al final de su adaptador de artículo:

<View
 android:layout_width="match_parent"
 android:layout_height="1dp"
 android:background="#FFFFFF"/>
Lucas Diego
fuente
25
Con esta solución obtendrá también la línea divisoria al final de la lista.
Arià
55
La última línea se puede eliminar mediante programación diciendo algo como esto en onBindViewHolder if(position == getItemCount() - 1) { mDividerView.setVisibility(View.INVISIBLE) }O debe haber otras formas de hacerlo.
Ali Kazi
la mayoría de las veces, la última línea 1pxde altura es invisible para nuestros ojos
Mehdi Khademloo
@LucasDiego Esto funcionará, pero sabemos que inflar es costoso.
Zohra Khan
21

Aquí está el código para un divisor personalizado simple (divisor vertical / 1dp de altura / negro):

Suponga que tiene una biblioteca de soporte:

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

código java

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

entonces la muestra del archivo 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>
Tobliug
fuente
10

Cree un archivo xml separado en la carpeta res / drawable

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

Conecte ese archivo xml (su_archivo) en la actividad principal , así:

DividerItemDecoration divider = new DividerItemDecoration(
    recyclerView.getContext(),
    DividerItemDecoration.VERTICAL
);
divider.setDrawable(ContextCompat.getDrawable(getBaseContext(), R.drawable.your_file));
recyclerView.addItemDecoration(divider);
Anushka Madusanka
fuente
¿Cómo agregar relleno? Usar relleno en forma no funciona.
Makalele
9

Versión Kotlin:

recyclerview.addItemDecoration(DividerItemDecoration(this, LinearLayoutManager.VERTICAL))
Duracell De Monaco
fuente
8

Creo que estás acostumbrado Fragmentsa tenerRecyclerView

Simplemente agregue estas líneas después de crear su RecyclerViewy LayoutManagerObjetos

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

¡Eso es!

Es compatible con las orientaciones HORIZONTAL y VERTICAL.

Vivek Maru
fuente
8

Prueba este sencillo código de línea única

recyclerView.addItemDecoration(new DividerItemDecoration(getContext(),LinearLayoutManager.VERTICAL)); 
Pravin Perumal
fuente
7

Necesita agregar la siguiente línea ...

mRecyclerView.addItemDecoration(new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL));
pablopatarca
fuente
7

La forma en que estoy manejando la vista del divisor y también los separadores del divisor es agregando una extensión RecyclerView.

1)

Agregue un nuevo archivo de extensión nombrando View o RecyclerView:

RecyclerViewExtension.kt

y agregue el setDividermétodo de extensión dentro del archivo 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)

Cree un archivo de recursos Drawable dentro del drawablepaquete como 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>

donde puede especificar el margen izquierdo y derecho en android:insetLefty android:insetRight.

3)

En su Actividad o Fragmento donde se inicializa RecyclerView, puede configurar el dibujo personalizado llamando a:

recyclerView.setDivider(R.drawable.recycler_view_divider)

4)

Saludos 🍺

RecyclerView fila con divisor.

Gent Berani
fuente
6

Entonces, esta podría no ser la forma correcta, pero acabo de agregar una vista a la vista de un solo elemento de RecyclerView (ya que no creo que haya una función incorporada) así:

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

Esto significa que cada elemento tendrá una línea que lo llena en su parte inferior. Lo hice aproximadamente 1dp de alto con un #111111fondo. Esto también le da una especie de efecto "3D".

Imponente
fuente
2
- esto no es una manera
Anand Tiwari
5

Puede crear un divisor reutilizable simple.

Crear divisor:

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

Crear línea divisoria: 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>

Agregue el divisor a su vista Recycler:

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

Para eliminar el divisor del último elemento:

Para evitar el dibujo del divisor para el último elemento, debe cambiar esta línea.

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

A

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

Su implementación final debería ser así:

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

Espero eso ayude:)

Bhuvanesh BS
fuente
1
Esto funciona perfectamente No sé por qué no es la respuesta aceptada
Kennedy Kambo
2

RecyclerView-FlexibleDivider de yqritc hace que este sea un trazador de líneas. Primero agregue esto a su build.gradle:

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

Ahora puede configurar y agregar un divisor donde configure el adaptador de su 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());
Gaurav Vachhani
fuente
16
@Gaurav, ¿dónde está HorizontalDividerItemDecorationubicada la clase?
iRuth
@ iRuth, debe agregar la biblioteca maven a su archivo .gradle github.com/yqritc/RecyclerView-FlexibleDivider
Hakem Zaied
55
Esta es una respuesta incompleta. Quizás sea apropiado un voto negativo.
Fin de semana
Es bueno mencionar que se requiere lib de tercera fiesta para eso @ gaurav-vachhani
Andrew V.
2

Por desgracia, Android solo complica las cosas pequeñas. La forma más fácil de lograr lo que desea, sin implementar DividerItemDecoration aquí:

Agregue el color de fondo al RecyclerView al color del divisor deseado:

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

Agregue el margen inferior (android: layout_marginBottom) a la raíz de diseño del elemento (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>

Esto debería dar espacio de 1dp entre los elementos y el color de fondo de RecyclerView (que es gris oscuro aparecería como divisor).

John Gummadi
fuente
1

Para que la respuesta de NJ sea un poco más simple, puede hacer:

public class DividerColorItemDecoration extends DividerItemDecoration {

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

Simplemente agregue un margen de x cantidad en la parte inferior de un elemento en su 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);
S Sathiya
fuente
1
recyclerview.addItemDecoration(new DividerItemDecoration(this, 0));

Donde 0es horizontal y 1es crítico

Freny Christian
fuente
3
use mejor la variable constante ya que el valor puede cambiar en la futura versión de la biblioteca de soporte
Irshu
cierto ... deberíamos usar LinearLayoutManager.HORIZONTAL o LinearLayoutManager.VERTICAL en lugar de 0 o 1
Freny Christian el
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)
                }
            }
        }
    }

Solo necesita especificar un color en 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>

y agréguelo a su reciclador

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

referir esto

Abhay Pratap
fuente
0

La solución Bhuvanesh BS funciona. Versión de Kotlin de esto:

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)
        }
    }
}
BestUserApps
fuente
0

creo que es la forma más fácil

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

Tenga en cuenta que: myshape puede ser rectangel con la altura que desea hacer su divisor

Abdelrahman Hussein
fuente