Как добавить разделительную линию в Android RecyclerView?

221

Я разрабатываю приложение для Android, где я использую RecyclerView. Мне нужно добавить разделитель в RecyclerView. Я пытался добавить -

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

ниже мой код XML -

   <android.support.v7.widget.RecyclerView
    android:id="@+id/drawerList"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="15dp"
    />
Sofquestion 8
источник
3
я думаю, это поможет вам stackoverflow.com/q/24618829/942224
Санкет Качела
Чтобы показать разделитель без последней строки, используйте это
Кишан Соланки
Я думаю, что ваш код правильный. Я не вижу никаких проблем.
Рохит Рават

Ответы:

282

В обновлении за октябрь 2016 года библиотека поддержки v25.0.0 теперь имеет стандартную реализацию основных горизонтальных и вертикальных разделителей!

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

 recyclerView.addItemDecoration(new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL));
Адитья Вьяс-Лахан
источник
3
Привет спасибо за информацию! Есть ли способ убрать разделитель после последнего элемента? У меня просто есть CardView, в котором реализован список, а разделитель + тень карты в нижней части выглядит не очень хорошо!
Макси
4
У меня была та же проблема, и я решил ее, расширив DividerItemDecoration и переопределив getItemOffsets, затем вызывая super, только если я не на первом элементе. if(parent.getChildAdapterPosition(view) == state.getItemCount() - 1)затем вернитесь, иначе вызовите суперкласс getItemOffsets().
Робин
13
Вместо этого mLayoutManager.getOrientation()я использовал, DividerItemDecoration.VERTICALи это сработало, так как мой RecyclerView является вертикальным.
Аарон Лелевье
2
Есть ли способ изменить цвет делителя, используя этот встроенный способ?
j2emanue
1
@ V.Kalyuzhnyu @android:attr/listDividerв теме приложения не отображает разделитель, если это ресурс цвета, мне пришлось создать форму, которую можно нарисовать моим цветом с фиксированной высотой.
А. Ферран
226

Правильный путь состоит в том, чтобы определить ItemDecorationдля RecyclerViewследующего

SimpleDividerItemDecoration.java

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

    public SimpleDividerItemDecoration(Context context) {
        mDivider = context.getResources().getDrawable(R.drawable.line_divider);
    }

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        int left = parent.getPaddingLeft();
        int right = parent.getWidth() - parent.getPaddingRight();

        int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = parent.getChildAt(i);

            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();

            int top = child.getBottom() + params.bottomMargin;
            int bottom = top + mDivider.getIntrinsicHeight();

            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }
}

line_divider.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <size
        android:width="1dp"
        android:height="1dp" />

    <solid android:color="@color/dark_gray" />

</shape>

Наконец, установите это так

recyclerView.addItemDecoration(new SimpleDividerItemDecoration(this));

редактировать

Как указано @Alan Solitar

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

амортизируется вместо того, что вы можете использовать

ContextCompat.getDrawable(context,R.drawable.line_divider);
Нью-Джерси
источник
3
context.getResources (). getDrawable (R.drawable.line_divider) больше не поддерживается.
Алан С.
2
Нет проблем. Это хороший ответ, и он отлично сработал для меня. Спасибо.
Алан С.
3
Это отлично работает на моей стороне. Однако мне интересно, почему бы не добавить простой <View> для этого разделителя в макет для каждой ячейки? Его гораздо меньше кода. Является ли это решение менее хорошим с точки зрения производительности? TX
Грег
4
Проблема с этой реализацией возникает, если вы пытаетесь смахивать или перемещать элементы вокруг.
Тернови
1
@NJ Спасибо, чувак, ты сэкономил мое время.
Сухас Бачевар
40

Если вы хотите иметь горизонтальные и вертикальные разделители:

  1. Определите горизонтальные и вертикальные разделители:

    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. Добавьте этот сегмент кода ниже:

    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);
Мухаммед Мухтар
источник
Это сработало. Но если вы измените horizontal_divider.xml, чтобы разделить ширину, и vertical_divider.xml, чтобы разделить высоту, вы можете создать каждый из них DividerItemDecorationследующим образом: verticalDecoration = new DividerItemDecoration(recyclerview.getContext(), DividerItemDecoration.VERTICAL);и horizontalDecoration = new DividerItemDecoration(recyclerview.getContext(), DividerItemDecoration.HORIZONTAL);.
Рубен О. Кьявоне
33

Все эти ответы приблизили меня, но в каждом из них отсутствовала ключевая деталь После небольшого исследования я обнаружил, что самым простым маршрутом является сочетание этих трех шагов:

  1. Используйте библиотеку поддержки DividerItemDecoration
  2. Создайте разделитель с правильным цветом
  3. Установите этот разделитель в своей теме как listDivider

Шаг 1: при настройке RecyclerView

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

Шаг 2: в файле, таком как res / drawable / divider_gray.xml

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

Шаг 3: в теме приложения

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

РЕДАКТИРОВАТЬ: Обновлено, чтобы пропустить последний разделитель:
После небольшого использования я понял, что это рисовать разделитель после последнего элемента, что раздражает. Поэтому я изменил Шаг 1 следующим образом, чтобы переопределить поведение по умолчанию в DividerItemDecoration (конечно, создание отдельного класса - это еще один вариант):

recyclerView.addItemDecoration(
        new DividerItemDecoration(context, layoutManager.getOrientation()) {
            @Override
            public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
                int position = parent.getChildAdapterPosition(view);
                // hide the divider for the last child
                if (position == parent.getAdapter().getItemCount() - 1) {
                    outRect.setEmpty();
                } else {
                    super.getItemOffsets(outRect, view, parent, state);
                }
            }
        }
);
gMale
источник
7
Переопределение getItemOffsets, похоже, не работает для меня. Даже если я переопределю и никогда не вызову супер, разделитель все равно будет нарисован. Не уверен, что изменилось.
lostintranslation
2
У меня это тоже не работает. Последний разделитель все еще показывает.
Сотти
1
В итоге я создал свой собственный класс делителя, скопировав источник DividerItemDecoration и немного изменив его, чтобы не рисовать последний делитель. В методе рисования просто игнорируйте последний дочерний вид: for (int i = 0; i < childCount; i++) измените наfor (int i = 0; i < childCount - 1; i++)
kientux
Поскольку ItemDecoration рисуется перед элементом списка («под» элементом списка), данное решение работает, только если ваш элемент списка имеет 100% -ный непрозрачный фон, или когда нарисованное украшение на 100% прозрачно (таким образом, пользователь видит фон recyclerView). В противном случае разделитель виден независимо от того, что вы возвращаете в getItemOffsets ()
ernazm
31

Просто добавьте View к концу вашего адаптера элемента:

<View
 android:layout_width="match_parent"
 android:layout_height="1dp"
 android:background="#FFFFFF"/>
Лукас Диего
источник
25
С этим решением вы также получите разделительную линию в конце списка.
Ария
5
Последняя строка может быть удалена программно, сказав что-то подобное в onBindViewHolder. if(position == getItemCount() - 1) { mDividerView.setVisibility(View.INVISIBLE) }Или должны быть другие способы сделать это.
Али Кази
Большую часть времени последняя строка с 1pxвысотой невидима для наших глаз
Мехди Хадемлу
@ LucasDiego Это сработает, но мы знаем, что надувать это дорого.
Зохра Хан
21

Вот код для простого пользовательского разделителя (вертикальный разделитель / 1dp высота / черный):

Предположим, у вас есть библиотека поддержки:

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

код Java

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

затем пример файла custom_divider.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
    <size android:height="1dp" />
    <solid android:color="@android:color/black" />
</shape>
Tobliug
источник
10

Создать отдельный файл XML в разрешении / вытяжке папка

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

Подключите этот XML-файл (your_file) к основному действию , например так:

DividerItemDecoration divider = new DividerItemDecoration(
    recyclerView.getContext(),
    DividerItemDecoration.VERTICAL
);
divider.setDrawable(ContextCompat.getDrawable(getBaseContext(), R.drawable.your_file));
recyclerView.addItemDecoration(divider);
Анушка Мадусанка
источник
Как добавить обивка? Использование отступов в форме не работает.
Makalele
9

Котлин Версия:

recyclerview.addItemDecoration(DividerItemDecoration(this, LinearLayoutManager.VERTICAL))
Duracell De Monaco
источник
8

Я думаю, что вы используете, Fragmentsчтобы иметьRecyclerView

Просто добавьте эти строки после создания ваших RecyclerViewи LayoutManagerобъектов

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

Это оно!

Он поддерживает как ГОРИЗОНТАЛЬНУЮ, так и ВЕРТИКАЛЬНУЮ ориентации.

Вивек Мару
источник
8

Попробуйте этот простой однострочный код

recyclerView.addItemDecoration(new DividerItemDecoration(getContext(),LinearLayoutManager.VERTICAL)); 
Правин Перумал
источник
7

Вам нужно добавить следующую строку ...

mRecyclerView.addItemDecoration(new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL));
pablopatarca
источник
7

Способ работы с представлением «Разделитель», а также «Вставки разделителя» заключается в добавлении расширения RecyclerView.

1.

Добавьте новый файл расширения с именем View или RecyclerView:

RecyclerViewExtension.kt

и добавьте setDividerметод расширения в файл RecyclerViewExtension.kt.

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


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

2.

Создайте файл ресурсов Drawable внутри drawableпакета, например recycler_view_divider.xml:

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

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

</inset>

где вы можете указать левый и правый край на android:insetLeftи android:insetRight.

3.

В вашей Деятельности или Фрагменте, где инициализируется RecyclerView, вы можете установить настраиваемое рисование, вызвав:

recyclerView.setDivider(R.drawable.recycler_view_divider)

4.

Приветствия 🍺

RecyclerView строка с разделителем.

Гент Берани
источник
6

Так что это может быть не правильным способом, но я просто добавил представление к представлению одного элемента RecyclerView (поскольку я не думаю, что есть встроенная функция), например так:

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

Это означает, что каждый элемент будет иметь линию, которая заполняет его в нижней части. Я сделал это около 1dp с #111111фоном. Это также дает своего рода «3D» эффект.

Smashing
источник
2
- это не путь
Ананд Тивари
5

Вы можете создать простой многоразовый разделитель.

Создать разделитель:

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

    public DividerItemDecorator(Drawable divider) {
        mDivider = divider;
    }

    @Override
    public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
        int dividerLeft = parent.getPaddingLeft();
        int dividerRight = parent.getWidth() - parent.getPaddingRight();

        int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = parent.getChildAt(i);

            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();

            int dividerTop = child.getBottom() + params.bottomMargin;
            int dividerBottom = dividerTop + mDivider.getIntrinsicHeight();

            mDivider.setBounds(dividerLeft, dividerTop, dividerRight, dividerBottom);
            mDivider.draw(canvas);
        }
    }
}

Создать разделительную линию: divr.xml

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

Добавьте разделитель в свой Recyclerview:

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

Чтобы удалить разделитель для последнего элемента:

Чтобы предотвратить рисование разделителя для последнего элемента, вы должны изменить эту строку.

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

к

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

Ваша окончательная реализация должна быть такой:

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

    public DividerItemDecorator(Drawable divider) {
        mDivider = divider;
    }

    @Override
    public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
        int dividerLeft = parent.getPaddingLeft();
        int dividerRight = parent.getWidth() - parent.getPaddingRight();

        int childCount = parent.getChildCount();
        for (int i = 0; i < childCount - 1; i++) {
            View child = parent.getChildAt(i);

            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();

            int dividerTop = child.getBottom() + params.bottomMargin;
            int dividerBottom = dividerTop + mDivider.getIntrinsicHeight();

            mDivider.setBounds(dividerLeft, dividerTop, dividerRight, dividerBottom);
            mDivider.draw(canvas);
        }
    }
}

Надеюсь, поможет:)

Бхуванеш Б.С.
источник
1
Это прекрасно работает, я не знаю, почему это не принятый ответ
Кеннеди Камбо
2

RecyclerView-FlexibleDivider от yqritc делает это одним вкладышем. Сначала добавьте это к себе build.gradle:

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

Теперь вы можете настроить и добавить делитель, в котором вы устанавливаете адаптер вашего recyclerView:

recyclerView.setAdapter(myAdapter);
recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(this).color(Color.RED).sizeResId(R.dimen.divider).marginResId(R.dimen.leftmargin, R.dimen.rightmargin).build());
Гаурав Вачани
источник
16
@Gaurav, где находится HorizontalDividerItemDecorationкласс?
iRuth
@iRuth, Вам нужно добавить библиотеку Maven в свой .gradle файл github.com/yqritc/RecyclerView-FlexibleDivider
Hakem Zaied
5
Это неполный ответ. Может быть, уместно голосование против.
выходные
Хорошо упомянуть, что для этого @ gaurav-vachhani требуется сторонняя библиотека,
Эндрю В.
2

Android просто делает мелочи слишком сложными, к сожалению. Самый простой способ достичь того, что вы хотите, без реализации DividerItemDecoration здесь:

Добавьте цвет фона в RecyclerView к желаемому цвету разделителя:

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

Добавьте нижнее поле (android: layout_marginBottom) в корневой макет элемента (list_item.xml):

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

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

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

</RelativeLayout>

Это должно дать 1dp пространство между элементами и цвет фона RecyclerView (темно-серый будет отображаться как разделитель).

Джон Гуммади
источник
1

Чтобы сделать ответ Нью-Джерси немного проще, вы можете сделать:

public class DividerColorItemDecoration extends DividerItemDecoration {

    public DividerColorItemDecoration(Context context, int orientation) {
        super(context, orientation);
        setDrawable(ContextCompat.getDrawable(context, R.drawable.line_divider));
    }
}
Уилл Пойтрас
источник
1

Просто добавьте поле в размере x в нижней части элемента в вашем RecycleView Adapter.

onCreateViewHolder

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

layoutParams.setMargins(0, 0, 0, 5);
itemView.setLayoutParams(layoutParams);
Сатия
источник
1
recyclerview.addItemDecoration(new DividerItemDecoration(this, 0));

Где 0горизонтальный и 1верный

Френи Кристиан
источник
3
лучше использовать постоянную переменную, так как значение может измениться в будущем выпуске библиотеки поддержки
Иршу
правда .. мы должны использовать LinearLayoutManager.HORIZONTAL или LinearLayoutManager.VERTICAL вместо 0 или 1
Freny Christian
0
  class ItemOffsetDecoration(
        context: Context,
        private val paddingLeft: Int,
        private val paddingRight: Int
    ) : RecyclerView.ItemDecoration() {
        private var mDivider: Drawable? = null

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

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

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

Вам просто нужно указать цвет в R.drawable.divider_medium

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

</shape>

и добавьте его в свой переработчикПросмотреть

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

ссылаться на это

Абхай Пратап
источник
0

Бхуванеш Б.С. Решение работ. Котлин версия этого:

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
источник
0

я думаю, что это самый простой способ

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

Обратите внимание, что: myshape может быть прямоугольным с высотой, которую вы хотите сделать разделителем

Абдельрахман Хуссейн
источник