Como uma linha divisória pode ser adicionada ao Android RecyclerView?

221

Estou desenvolvendo um aplicativo Android onde estou usando RecyclerView. Eu preciso adicionar um divisor no RecyclerView. Eu tentei adicionar -

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

abaixo está o meu 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
fonte
3
i guees isso vai ajudar você stackoverflow.com/q/24618829/942224
Sanket Kachhela
Para mostrar divisor sem a última linha, use este
Kishan Solanki
Eu acho que seu código está correto. Não vejo nenhum problema.
Rohit Rawat

Respostas:

282

Na atualização de outubro de 2016, a biblioteca de suporte v25.0.0 agora possui uma implementação padrão de divisores horizontais e verticais básicos disponíveis!

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

 recyclerView.addItemDecoration(new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL));
Aditya Vyas-Lakhan
fonte
3
Oi obrigado pela informação! Existe uma maneira de remover o divisor após o último item? Eu só tenho um CardView onde a lista é implementada e o divisor + sombra do cardview na parte inferior não parece bom!
Max6
4
Eu tive o mesmo problema e resolvi-o estendendo DividerItemDecoration e substituindo getItemOffsets, depois chamando super se não estiver no primeiro item. if(parent.getChildAdapterPosition(view) == state.getItemCount() - 1)depois retorne, caso contrário, chame a superclasse ' getItemOffsets().
Robin
13
Em vez disso mLayoutManager.getOrientation(), usei DividerItemDecoration.VERTICALe funcionou, pois meu RecyclerView é vertical.
Aaron Lelevier
2
existe uma maneira de mudar a cor do divisor usando isso construído de maneira?
J2emanue 19/06
1
@ V.Kalyuzhnyu @android:attr/listDividerno tema do aplicativo não exibe um divisor, se for um recurso de cores, tive que criar uma forma que pode ser desenhada com a minha cor com uma altura fixa.
A.Randand #
226

O caminho certo é definir ItemDecorationo RecyclerViewseguinte:

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, defina-o assim

recyclerView.addItemDecoration(new SimpleDividerItemDecoration(this));

Editar

Como apontado por @Alan Solitar

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

é depreciado em vez de que você pode usar

ContextCompat.getDrawable(context,R.drawable.line_divider);
NJ
fonte
3
context.getResources (). getDrawable (R.drawable.line_divider) agora está obsoleto.
Alan S.
2
Sem problemas. Esta é uma boa resposta e funcionou perfeitamente para mim. Obrigado.
Alan S.
3
Isso está funcionando perfeitamente do meu lado. No entanto, gostaria de saber por que não adicionar um <View> simples para esse separador no layout de cada célula? É muito menos código. Esta solução é menos eficiente em termos de desempenho? tx
Greg
4
Problema com esta implementação surge se você tentar deslizar ou mover itens.
TerNovi 27/06
1
@NJ Obrigado cara, você economizou meu tempo.
Suhas Bachewar
40

Se você deseja ter divisores horizontais e verticais:

  1. Defina drawables divisores horizontais e verticais:

    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. Adicione este segmento de código abaixo:

    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
fonte
Funcionou. Mas se você alterar horizontal_divider.xml para dividir a largura e vertical_divider.xml para dividir a altura, poderá criar cada um DividerItemDecorationassim: verticalDecoration = new DividerItemDecoration(recyclerview.getContext(), DividerItemDecoration.VERTICAL);e horizontalDecoration = new DividerItemDecoration(recyclerview.getContext(), DividerItemDecoration.HORIZONTAL);.
Ruben O. Chiavone
33

Todas essas respostas me aproximaram, mas cada uma delas estava com falta de um detalhe importante. Depois de um pouco de pesquisa, achei a rota mais fácil para ser uma combinação dessas três etapas:

  1. Use o DividerItemDecoration da biblioteca de suporte
  2. Crie um divisor com a cor certa
  3. Defina esse divisor no seu tema como a listaDivider

Etapa 1: ao configurar o RecyclerView

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

Etapa 2: em um arquivo 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>

Etapa 3: no tema do aplicativo

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

EDIT: Atualizado para pular o último divisor:
Depois de usar isso um pouco, percebi que ele estava desenhando um divisor após o último item, o que era irritante. Então, modifiquei a Etapa 1 da seguinte maneira para substituir esse comportamento padrão no DividerItemDecoration (é claro, criar uma classe separada é outra opção):

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
fonte
7
Substituir getItemOffsets não parece funcionar para mim. Mesmo se eu substituir e nunca chamar de super, o divisor ainda está desenhado. Não tenho certeza do que mudou.
lostintranslation
2
Também não funciona para mim. O último divisor ainda está sendo exibido.
Sotti 27/02
1
Acabei criando minha própria classe divisora, copiando a fonte de DividerItemDecoration e alterei um pouco para não desenhar o último divisor. No método de desenho, ignore a última visão filho: for (int i = 0; i < childCount; i++) mude parafor (int i = 0; i < childCount - 1; i++)
kientux 31/03/18
Como ItemDecoration é desenhado antes do item da lista ("abaixo" do item da lista), a solução fornecida funciona apenas se o item da lista tiver um fundo 100% opaco ou quando o desenho da decoração for 100% transparente (para que o usuário veja o fundo do recyclerView). Caso contrário, o divisor é visível não importa o que você retornar em getItemOffsets ()
ernazm
31

Basta adicionar uma View no final do seu adaptador de itens:

<View
 android:layout_width="match_parent"
 android:layout_height="1dp"
 android:background="#FFFFFF"/>
Lucas Diego
fonte
25
Com esta solução, você também terá a linha divisória no final da lista.
Arià
5
A última linha pode ser removida programaticamente dizendo algo parecido com isto em onBindViewHolder if(position == getItemCount() - 1) { mDividerView.setVisibility(View.INVISIBLE) }Ou deve haver outras maneiras de fazer isso.
Ali Kazi
na maioria das vezes, a última linha com o 1pxde altura, é invisível aos nossos olhos
Mehdi Khademloo
@LucasDiego Isso funcionará, mas sabemos que inflar é caro.
21418 Zohra Khan
21

Aqui está o código para um divisor personalizado simples (divisor vertical / 1dp de altura / preto):

Supõe que você tenha a Biblioteca de Suporte:

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

a amostra do arquivo 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
fonte
10

Crie um arquivo xml separado na pasta 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 esse arquivo xml (your_file) na atividade principal , assim:

DividerItemDecoration divider = new DividerItemDecoration(
    recyclerView.getContext(),
    DividerItemDecoration.VERTICAL
);
divider.setDrawable(ContextCompat.getDrawable(getBaseContext(), R.drawable.your_file));
recyclerView.addItemDecoration(divider);
Anushka Madusanka
fonte
Como adicionar preenchimento? Usar preenchimento em forma não funciona.
Makalele 8/11
9

Versão Kotlin:

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

Eu acho que você está usando Fragmentspara terRecyclerView

Basta adicionar estas linhas depois de criar os seus RecyclerViewe LayoutManagerObjetos

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

É isso aí!

Ele suporta as orientações HORIZONTAL e VERTICAL.

Vivek Maru
fonte
8

Experimente este código simples de linha única

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

Você precisa adicionar a próxima linha ...

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

A maneira como estou lidando com a exibição do divisor e também com os insertos do divisor é adicionando uma extensão RecyclerView.

1

Adicione um novo arquivo de extensão nomeando View ou RecyclerView:

RecyclerViewExtension.kt

e adicione o setDividermétodo de extensão dentro do arquivo 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)

Crie um arquivo de recurso Drawable dentro do drawablepacote, 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>

onde você pode especificar as margens esquerda e direita em android:insetLefte android:insetRight.

3)

Na sua Atividade ou Fragmento onde o RecyclerView é inicializado, você pode definir o drawable personalizado chamando:

recyclerView.setDivider(R.drawable.recycler_view_divider)

4)

Saúde 🍺

Linha RecyclerView com divisor.

Gent Berani
fonte
6

Portanto, essa pode não ser a maneira correta, mas acabei de adicionar uma exibição à exibição de item único do RecyclerView (como não acho que exista uma função interna) assim:

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

Isso significa que cada item terá uma linha que o preenche na parte inferior. Eu consegui 1dp de altura com um #111111fundo. Isso também fornece um tipo de efeito "3D".

Smashing
fonte
2
- isso não é uma maneira
Anand Tiwari
5

Você pode criar um divisor reutilizável simples.

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

Criar linha divisória: 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>

Adicione o divisor à sua Recyclerview:

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

Para remover o divisor para o último item:

Para impedir o desenho do divisor para o último item, é necessário alterar esta linha.

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

Para

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

Sua implementação final deve ser assim:

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

Bhuvanesh BS
fonte
1
Isso funciona perfeitamente Eu não sei por que não é a resposta aceita
Kennedy Kambo
2

O RecyclerView-FlexibleDivider do yqritc faz deste um liner. Primeiro adicione isso ao seu build.gradle:

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

Agora você pode configurar e adicionar uma divisória onde define o adaptador do seu 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
fonte
16
@ Gaurav, onde está HorizontalDividerItemDecorationlocalizada a turma?
IRuth
@iRuth, Você precisa adicionar a biblioteca Maven em seu arquivo .gradle github.com/yqritc/RecyclerView-FlexibleDivider
Hakem Zaied
5
Esta é uma resposta incompleta. Talvez uma votação negativa seja apropriada.
Weekend
É bom mencionar que 3-rd partido lib necessário para que @ gaurav-Vachhani
Andrew V.
2

Infelizmente, o Android simplifica muito as coisas. A maneira mais fácil de alcançar o que você deseja, sem implementar o DividerItemDecoration aqui:

Adicione cor de plano de fundo ao RecyclerView à sua cor divisória desejada:

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

Adicione a margem inferior (android: layout_marginBottom) à raiz do layout do item (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>

Isso deve dar 1dp de espaço entre os itens e a cor de fundo do RecyclerView (que é cinza escuro aparecerá como divisor).

John Gummadi
fonte
1

Para tornar a resposta de NJ um pouco mais simples, você pode fazer:

public class DividerColorItemDecoration extends DividerItemDecoration {

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

Basta adicionar uma margem de x quantidade na parte inferior de um item no seu 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
fonte
1
recyclerview.addItemDecoration(new DividerItemDecoration(this, 0));

Onde 0é Horizontal e 1é Verítico

Freny Christian
fonte
3
melhor usar a variável constante como o valor pode mudar no futuro lançamento da biblioteca de suporte
Irshu
verdade .. devemos usar LinearLayoutManager.HORIZONTAL ou LinearLayoutManager.VERTICAL em vez de 0 ou 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)
                }
            }
        }
    }

Você só precisa especificar uma cor em 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 adicione-o ao seu reciclador

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

refernce isto

Abhay Pratap
fonte
0

A solução Bhuvanesh BS funciona. Versão Kotlin disso:

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
fonte
0

eu acho que é a maneira mais fácil

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

Observe que: myshape pode ser retangular com a altura que você deseja criar seu divisor

Abdelrahman Hussein
fonte