Come si può aggiungere una linea divisoria in un RecyclerView per Android?


221

Sto sviluppando un'applicazione Android dove sto usando RecyclerView. Devo aggiungere un divisore in RecyclerView. Ho provato ad aggiungere -

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

sotto è il mio codice 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
Ho guees questo vi aiuterà a stackoverflow.com/q/24618829/942224
Sanket Kachhela

Per mostrare il divisore senza l'ultima riga, usa questo
Kishan Solanki il

Penso che il tuo codice sia corretto. Non vedo alcun problema.
Rohit Rawat,

Risposte:


282

Nell'aggiornamento di ottobre 2016, la libreria di supporto v25.0.0 ora ha un'implementazione predefinita di divisori orizzontali e verticali di base disponibili!

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

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

3
Ciao grazie per l'informazione! C'è un modo per rimuovere il divisore dopo l'ultimo elemento? Ho solo un CardView in cui è implementato l'elenco e il divisore + ombra di cardview in fondo non sembra buono!
Maxi

4
Ho avuto lo stesso problema e l'ho risolto estendendo DividerItemDecoration e sovrascrivendo getItemOffsets, quindi chiamando super solo se non sono sul primo elemento. if(parent.getChildAdapterPosition(view) == state.getItemCount() - 1)poi ritorna, altrimenti chiama la superclasse ' getItemOffsets().
Robin,

13
Invece mLayoutManager.getOrientation(), ho usato DividerItemDecoration.VERTICALe ha funzionato, dal momento che il mio RecyclerView è verticale.
Aaron Lelevier,

2
c'è un modo per cambiare il colore del divisore usando questo modo integrato?
j2emanue,

1
@ V.Kalyuzhnyu @android:attr/listDividernel tema dell'app non visualizza un divisore se si tratta di una risorsa colore, ho dovuto creare una forma disegnabile con il mio colore con un'altezza fissa.
A. Ferrand,

226

Il modo giusto è definire ItemDecorationper ilRecyclerView seguente

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 impostalo così

recyclerView.addItemDecoration(new SimpleDividerItemDecoration(this));

modificare

Come sottolineato da @Alan Solitar

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

è ammortizzato invece che è possibile utilizzare

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

3
context.getResources (). getDrawable (R.drawable.line_divider) è ora obsoleto.
Alan S.

2
Nessun problema. Questa è una buona risposta e ha funzionato perfettamente per me. Grazie.
Alan S.

3
Questo funziona perfettamente dalla mia parte. Tuttavia, mi chiedo perché non aggiungere un semplice <View> per questo separatore nel layout per ogni cella? È molto meno codice. Questa soluzione è meno saggia in termini di prestazioni? tx
Greg,

4
Il problema con questa implementazione sorge se si tenta di scorrere o spostare gli oggetti.
TerNovi,

1
@NJ Grazie amico, mi hai risparmiato tempo.
Suhas Bachewar,

40

Se vuoi avere divisori sia orizzontali che verticali:

  1. Definire drawable divisori orizzontali e verticali:

    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. Aggiungi questo segmento di codice di seguito:

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

Ha funzionato. Ma se cambiate horizontal_divider.xml per dividere larghezza e vertical_divider.xml per dividere l'altezza, è possibile crearli in DividerItemDecorationquesto modo: verticalDecoration = new DividerItemDecoration(recyclerview.getContext(), DividerItemDecoration.VERTICAL);e horizontalDecoration = new DividerItemDecoration(recyclerview.getContext(), DividerItemDecoration.HORIZONTAL);.
Ruben O. Chiavone,

33

Tutte queste risposte mi hanno avvicinato ma mancavano ognuna un dettaglio chiave. Dopo un po 'di ricerca, ho trovato il percorso più semplice per essere una combinazione di questi 3 passaggi:

  1. Utilizzare DividerItemDecoration della libreria di supporto
  2. Crea un divisore con il colore giusto
  3. Imposta questo divisore nel tuo tema come listDivider

Passaggio 1: durante la configurazione di RecyclerView

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

Passaggio 2: in un file come 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>

Passaggio 3: nel tema dell'app

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

EDIT: Aggiornato per saltare l'ultimo divisore:
dopo averlo usato un po ', mi sono reso conto che stava disegnando un divisore dopo l'ultimo elemento, il che era fastidioso. Quindi ho modificato il passaggio 1 come segue per sovrascrivere quel comportamento predefinito in DividerItemDecoration (ovviamente, creare un'altra classe è un'altra opzione):

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
La sostituzione di getItemOffsets non sembra funzionare per me. Anche se eseguo l'override e non chiamo mai super, il divisore viene comunque disegnato. Non sono sicuro di cosa sia cambiato.
lostintranslation

2
Neanche per me funziona. L'ultimo divisore viene ancora mostrato.
Sotti,

1
Ho finito per creare la mia classe divisoria copiando l'origine di DividerItemDecoration e cambiando un po 'per non disegnare l'ultimo dividendo. Nel metodo di disegno, ignora solo l'ultima vista figlio: for (int i = 0; i < childCount; i++) passa afor (int i = 0; i < childCount - 1; i++)
kientux il

Poiché ItemDecoration viene disegnato prima dell'elemento dell'elenco ("sotto" l'elemento dell'elenco), la soluzione data funziona solo se l'elemento dell'elenco ha uno sfondo opaco al 100% o quando il disegno decorativo è trasparente al 100% (quindi l'utente vede lo sfondo di recyclerView). Altrimenti il ​​divisore è visibile, non importa cosa ritorni in getItemOffsets ()
ernazm,

31

Aggiungi una vista alla fine dell'adattatore per articoli:

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

25
Con questa soluzione otterrai anche la linea di divisione alla fine dell'elenco.
Arià,

5
L'ultima riga può essere rimossa in modo programmatico dicendo qualcosa del genere in onBindViewHolder if(position == getItemCount() - 1) { mDividerView.setVisibility(View.INVISIBLE) }O ci devono essere altri modi per farlo.
Ali Kazi,

la maggior parte delle volte, l'ultima linea 1pxdi altezza, è invisibile ai nostri occhi
Mehdi Khademloo

@LucasDiego Funzionerà ma sappiamo che gonfiare è costoso.
Zohra Khan,

21

Ecco il codice per un semplice divisore personalizzato (divisore verticale / altezza 1dp / nero):

Supponiamo che tu abbia la libreria di supporto:

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

codice java

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

quindi l'esempio di file 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

Crea un file xml separato nella cartella 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>

Connetti quel file xml (your_file) all'attività principale , in questo modo:

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

Come aggiungere l'imbottitura? L'uso dell'imbottitura in forma non funziona.
Makalele,

9

Versione di Kotlin:

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

8

Penso che stai usando Fragmentsper avereRecyclerView

Aggiungi semplicemente queste righe dopo aver creato your RecyclerViewe LayoutManagerObjects

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

Questo è tutto!

Supporta entrambi gli orientamenti ORIZZONTALE e VERTICALE.


8

Prova questo semplice codice a riga singola

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

7

Devi aggiungere la riga successiva ...

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

7

Il modo in cui gestisco la vista Divider e anche Divider Insets è aggiungendo un'estensione RecyclerView.

1.

Aggiungi un nuovo file di estensione nominando Visualizza o RecyclerView:

RecyclerViewExtension.kt

e aggiungi il setDividermetodo di estensione all'interno del file 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.

Crea un file di risorse Drawable all'interno del drawablepacchetto come 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>

dove è possibile specificare il margine sinistro e destro su android:insetLefte android:insetRight.

3.

Nella tua attività o frammento in cui è inizializzato RecyclerView, puoi impostare il disegno personalizzato chiamando:

recyclerView.setDivider(R.drawable.recycler_view_divider)

4.

Saluti 🍺

Riga RecyclerView con divisore.


6

Quindi questo potrebbe non essere il modo corretto, ma ho appena aggiunto una vista alla vista a singolo elemento di RecyclerView (poiché non credo che ci sia una funzione integrata) in questo modo:

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

Ciò significa che ogni articolo avrà una linea che lo riempie in fondo. L'ho fatto alto circa 1dp con uno #111111sfondo. Questo dà anche una sorta di effetto "3D".


2
- questo non è un modo
Anand Tiwari il

5

È possibile creare un divisore riutilizzabile semplice.

Crea divisore:

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

Crea linea 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>

Aggiungi divisore al tuo Recyclerview:

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

Per rimuovere il divisore per l'ultimo elemento:

Per evitare il disegno del divisore per l'ultimo elemento devi cambiare questa linea.

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

Per

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

L'implementazione finale dovrebbe essere così:

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

Spero che sia d'aiuto:)


1
Funziona perfettamente, non so perché non sia la risposta accettata
Kennedy Kambo,

2

RecyclerView-FlexibleDivider di yqritc lo rende unico. Per prima cosa aggiungi questo al tuo build.gradle:

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

Ora puoi configurare e aggiungere un operatore subacqueo in cui hai impostato l'adattatore di 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, dove si trova la HorizontalDividerItemDecorationclasse?
iRuth,

@iRuth, devi aggiungere la libreria maven nel tuo file .gradle github.com/yqritc/RecyclerView-FatileDivider
Hakem Zaied

5
Questa è una risposta incompleta. Forse un voto negativo è appropriato.
Weekend

È bene ricordare che è richiesta la lib di terze parti per quel @ gaurav-vachhani
Andrew V.

2

Sfortunatamente Android rende le piccole cose troppo complicate. Il modo più semplice per ottenere ciò che desideri, senza implementare DividerItemDecoration qui:

Aggiungi il colore di sfondo al RecyclerView al colore del tuo divisore desiderato:

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

Aggiungi il margine inferiore (android: layout_marginBottom) alla radice del layout dell'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>

Questo dovrebbe dare 1dp di spazio tra gli oggetti e il colore di sfondo di RecyclerView (che sarebbe grigio scuro apparirebbe come divisore).


1

Per rendere la risposta di NJ un po 'più semplice puoi fare:

public class DividerColorItemDecoration extends DividerItemDecoration {

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

1

Aggiungi semplicemente un margine di x quantità nella parte inferiore di un articolo nel tuo 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));

Dov'è 0orizzontale ed 1è verticale


3
utilizzare meglio la variabile costante poiché il valore potrebbe cambiare nella versione futura della libreria di supporto
Irshu,

vero .. dovremmo usare LinearLayoutManager.HORIZONTAL o LinearLayoutManager.VERTICAL invece di 0 o 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)
                }
            }
        }
    }

Devi solo specificare un colore in 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>

e aggiungilo al tuo recyclerView

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

fare riferimento a questo


0

La soluzione Bhuvanesh BS funziona. Versione Kotlin di questo:

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

penso che sia il modo più semplice

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

Nota che: myshape può essere rettangolare con l'altezza che vuoi rendere il tuo divisore

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.