Разделители и отступы в RecyclerView: Полное руководство
Узнайте, как добавлять разделители и отступы между элементами RecyclerView с помощью классов ItemDecoration. Полное руководство с примерами кода для LinearLayoutManager и GridLayoutManager.
Как добавить разделители и отступы между элементами в RecyclerView
В разработке под Android я пытаюсь добавить разделители и отступы между элементами в RecyclerView, аналогично тому, как это делалось с ListView с помощью параметров divider и dividerHeight:
<ListView
android:id="@+id/activity_home_list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@android:color/transparent"
android:dividerHeight="8dp"/>
Однако я не вижу эквивалентных свойств в классе RecyclerView:
<android.support.v7.widget.RecyclerView
android:id="@+id/activity_home_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"/>
Какой рекомендуемый подход для добавления разделителей и отступов между элементами в RecyclerView? Следует ли определять отступы и/или добавлять пользовательский вид разделителя прямо в макет элемента списка, или есть более лучший способ добиться этого?
Чтобы добавлять разделители и отступы между элементами в RecyclerView, необходимо использовать классы ItemDecoration, а не XML-атрибуты, как в ListView. Рекомендуемые подходы включают использование встроенного DividerItemDecoration из библиотеки Android Support Library, создание пользовательских классов ItemDecoration для большего контроля или реализацию отступов через поля в макетах элементов.
Содержание
- Использование DividerItemDecoration
- Создание пользовательских ItemDecorations
- Добавление отступов между элементами
- Особенности GridLayoutManager
- Варианты разделителей Material Design
- Лучшие практики и рекомендации
Использование DividerItemDecoration
Простой подход - использование встроенного класса DividerItemDecoration из библиотеки Android Support Library. Это предоставляет стандартный разделитель между элементами для LinearLayoutManager.
Реализация:
// В вашем Activity или Fragment
RecyclerView recyclerView = findViewById(R.id.activity_home_recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
// Добавление декорации разделителя
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(
recyclerView.getContext(),
DividerItemDecoration.VERTICAL
);
recyclerView.addItemDecoration(dividerItemDecoration);
Настройка внешнего вида разделителя:
Вы можете создать пользовательский drawable разделителя в папке res/drawable:
<!-- res/drawable/custom_divider.xml -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="line">
<size android:height="1dp" android:width="1dp"/>
<solid android:color="#CCCCCC"/>
</shape>
Затем используйте его в вашем пользовательском разделителе:
public class CustomDividerItemDecoration extends RecyclerView.ItemDecoration {
private Drawable divider;
public CustomDividerItemDecoration(Context context, int resId) {
divider = ContextCompat.getDrawable(context, resId);
}
@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 + divider.getIntrinsicHeight();
divider.setBounds(left, top, right, bottom);
divider.draw(c);
}
}
}
Создание пользовательских ItemDecorations
Для большего контроля над разделителями и отступами вы можете создавать пользовательские классы ItemDecoration, расширяя RecyclerView.ItemDecoration.
Базовый пользовательский ItemDecoration:
public class SimpleItemDecorator extends RecyclerView.ItemDecoration {
private int space;
private boolean isHorizontalLayout;
public SimpleItemDecorator(int space) {
this.space = space;
}
public SimpleItemDecorator(int space, boolean isHorizontalLayout) {
this.space = space;
this.isHorizontalLayout = isHorizontalLayout;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
outRect.bottom = space;
outRect.right = space;
outRect.left = space;
outRect.top = space;
}
}
Условный разделитель для последнего элемента:
public class ConditionalDividerDecoration extends RecyclerView.ItemDecoration {
private Drawable divider;
private int verticalSpaceHeight;
public ConditionalDividerDecoration(Context context, int verticalSpaceHeight) {
this.verticalSpaceHeight = verticalSpaceHeight;
// Получение разделителя по умолчанию
TypedArray styledAttributes = context.obtainStyledAttributes(
new int[]{android.R.attr.listDivider});
divider = styledAttributes.getDrawable(0);
styledAttributes.recycle();
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (parent.getChildAdapterPosition(view) != parent.getAdapter().getItemCount() - 1) {
outRect.bottom = verticalSpaceHeight;
}
}
@Override
public void onDraw(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 - 1; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int top = child.getBottom() + params.bottomMargin;
int bottom = top + divider.getIntrinsicHeight();
divider.setBounds(left, top, right, bottom);
divider.draw(c);
}
}
}
Добавление отступов между элементами
Для добавления отступов между элементами без разделителей можно использовать более простой ItemDecoration:
public class VerticalSpaceItemDecoration extends RecyclerView.ItemDecoration {
private final int verticalSpaceHeight;
public VerticalSpaceItemDecoration(int verticalSpaceHeight) {
this.verticalSpaceHeight = verticalSpaceHeight;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (parent.getChildAdapterPosition(view) != parent.getAdapter().getItemCount() - 1) {
outRect.bottom = verticalSpaceHeight;
}
}
}
Использование:
recyclerView.addItemDecoration(new VerticalSpaceItemDecoration(48)); // 48dp отступ
Особенности GridLayoutManager
При использовании GridLayoutManager требуется специальная обработка для разделителей и отступов:
public class GridSpacesItemDecoration extends RecyclerView.ItemDecoration {
private int space;
public GridSpacesItemDecoration(int space) {
this.space = space;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view);
int spanCount = ((GridLayoutManager) parent.getLayoutManager()).getSpanCount();
int column = position % spanCount;
// Добавление отступов слева и справа
outRect.left = column * space / spanCount;
outRect.right = space - (column + 1) * space / spanCount;
// Добавление верхнего отступа для первой строки
if (position < spanCount) {
outRect.top = space;
}
outRect.bottom = space;
}
}
Варианты разделителей Material Design
Для более новых реализаций Material Design рассмотрите использование MaterialDividerItemDecoration:
// Для Material Components
MaterialDividerItemDecoration dividerDecoration = new MaterialDividerItemDecoration(
requireContext(),
DividerItemDecoration.VERTICAL
);
dividerDecoration.setLastItemDecorated(false); // Не рисовать после последнего элемента
dividerDecoration.setDividerColor(Color.parseColor("#CCCCCC"));
dividerDecoration.setDividerInsetStart(16);
dividerDecoration.setDividerInsetEnd(16);
recyclerView.addItemDecoration(dividerDecoration);
Лучшие практики и рекомендации
-
Используйте ItemDecoration для последовательных отступов: ItemDecorations рисуются RecyclerView и остаются последовательными при прокрутке и изменении элементов.
-
Обрабатывайте крайние случаи: Всегда учитывайте первый и последний элементы при реализации разделителей.
-
Вопросы производительности: Сложные операции
onDrawмогут повлиять на производительность. Делайте рисование разделителей простым. -
Разные подходы для разных нужд:
- Для простых разделителей: Используйте
DividerItemDecoration - Для пользовательских отступов: Создавайте пользовательские
ItemDecoration - Для Material Design: Используйте
MaterialDividerItemDecoration - Для сеток: Используйте специализированные декораторы сеток
- Для простых разделителей: Используйте
-
Избегайте добавления разделителей в макеты элементов: Добавление представлений разделителей в индивидуальные макеты создает проблемы с производительностью и непоследовательное поведение.
-
Учитывайте доступность: Убедитесь, что разделители не мешают функциям доступности, предоставляя правильное группирование контента.
Пример реализации, сочетающий отступы и разделители:
// В настройке вашего Activity/Fragment
RecyclerView recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
// Добавление отступов
recyclerView.addItemDecoration(new VerticalSpaceItemDecoration(16));
// Добавление разделителей
recyclerView.addItemDecoration(new DividerItemDecoration(
this,
DividerItemDecoration.VERTICAL
));
Ключевое отличие от ListView заключается в том, что RecyclerView использует более гибкую и мощную систему ItemDecoration, которая позволяет лучше настраивать и обеспечивает лучшую производительность, но требует программной настройки вместо простых XML-атрибутов.
Источники
- Как добавить разделители и отступы между элементами в RecyclerView - Stack Overflow
- DividerItemDecoration | Android Developers
- Как добавить разделители в Android RecyclerView - GeeksforGeeks
- RecyclerView ItemDecoration: Максимизация возможностей - Medium
- Добавление разделителей и отступов между элементами в RecyclerView - Ready Android
- Реализация DividerItemDecoration - GitHub
Заключение
Чтобы добавлять разделители и отступы между элементами RecyclerView:
- Начните с
DividerItemDecorationдля простых разделителей - Создавайте пользовательские классы
ItemDecorationдля расширенного контроля - Используйте
getItemOffsets()для отступов иonDraw()для пользовательских разделителей - Рассмотрите
MaterialDividerItemDecorationдля приложений Material Design - Обрабатывайте крайние случаи, такие как первый/последний элементы и сценарии GridLayoutManager
- Избегайте добавления разделителей непосредственно в макеты элементов для лучшей производительности
Система ItemDecoration обеспечивает большую гибкость, чем встроенные свойства разделителей ListView, позволяя лучше настраивать и обеспечивая последовательное поведение в разных менеджерах компоновки.