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

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

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

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

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

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

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>

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

¿Cómo agregar relleno? Usar relleno en forma no funciona.
Makalele

9

Versión Kotlin:

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

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.


8

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

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

7

Necesita agregar la siguiente línea ...

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

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.


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


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


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

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


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

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

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

Donde 0es horizontal y 1es crítico


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


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

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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.