Как добавить разделители и пробелы между элементами в 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"/>
В этом случае, нормально ли определять поля и/или добавлять пользовательский вид разделителя непосредственно в макет элемента списка или есть лучший способ достичь моей цели?
Ответы
Ответ 1
Обновление за октябрь 2016 года
В версии 25.0.0 библиотеки поддержки Android появился класс DividerItemDecoration
:
DividerItemDecoration - это RecyclerView.ItemDecoration, которое можно использовать в качестве разделителя между элементами LinearLayoutManager
. Он поддерживает ориентации HORIZONTAL
и VERTICAL
.
Применение:
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
layoutManager.getOrientation());
recyclerView.addItemDecoration(dividerItemDecoration);
Предыдущий ответ
В некоторых ответах либо используются методы, которые с тех пор устарели, либо они не дают полного решения, поэтому я попытался сделать краткую актуальную сводку.
В отличие от ListView
, класс RecyclerView
не имеет параметров, связанных с делителем. Вместо этого вам нужно расширить ItemDecoration
, внутренний класс RecyclerView
:
ItemDecoration
позволяет приложению добавлять специальный чертеж и смещение макета к конкретным представлениям элементов из набора данных адаптера. Это может быть полезно для рисования разделителей между элементами, бликами, границами визуальной группировки и многим другим.
Все ItemDecorations
отрисовываются в том порядке, в котором они были добавлены, перед представлениями элементов (в onDraw()
) и после элементов (в onDrawOver (Canvas
, RecyclerView
, RecyclerView.State)
.
).Vertical
интервал ItemDecoration
Расширьте ItemDecoration
, добавьте пользовательский конструктор, который занимает пространство height
в качестве параметра, и переопределите метод getItemOffsets()
:
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) {
outRect.bottom = verticalSpaceHeight;
}
}
Если вы не хотите вставлять пробел под последним элементом, добавьте следующее условие:
if (parent.getChildAdapterPosition(view) != parent.getAdapter().getItemCount() - 1) {
outRect.bottom = verticalSpaceHeight;
}
Примечание. Вы также можете изменить свойства outRect.top
, outRect.left
и outRect.right
для достижения желаемого эффекта.
Делитель ItemDecoration
Расширьте ItemDecoration
и переопределите метод onDraw()
:
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private static final int[] ATTRS = new int[]{android.R.attr.listDivider};
private Drawable divider;
/**
* Default divider will be used
*/
public DividerItemDecoration(Context context) {
final TypedArray styledAttributes = context.obtainStyledAttributes(ATTRS);
divider = styledAttributes.getDrawable(0);
styledAttributes.recycle();
}
/**
* Custom divider will be used
*/
public DividerItemDecoration(Context context, int resId) {
divider = ContextCompat.getDrawable(context, resId);
}
@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; 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);
}
}
}
Вы можете вызвать либо первый конструктор, который использует атрибуты делителя Android по умолчанию, либо второй, который использует ваш собственный drawable, например drawable/divr.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="#ff992900" />
</shape>
Примечание. Если вы хотите, чтобы разделитель отображался поверх ваших элементов, вместо этого переопределите метод onDrawOver()
.
ИспользованиеЧтобы использовать новый класс, добавьте VerticalSpaceItemDecoration
или DividerSpaceItemDecoration
в RecyclerView
, например, в методе фрагмента onCreateView()
:
private static final int VERTICAL_ITEM_SPACE = 48;
private RecyclerView recyclerView;
private LinearLayoutManager linearLayoutManager;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_feed, container, false);
recyclerView = (RecyclerView) rootView.findViewById(R.id.fragment_home_recycler_view);
linearLayoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(linearLayoutManager);
//add ItemDecoration
recyclerView.addItemDecoration(new VerticalSpaceItemDecoration(VERTICAL_ITEM_SPACE));
//or
recyclerView.addItemDecoration(new DividerItemDecoration(getActivity()));
//or
recyclerView.addItemDecoration(
new DividerItemDecoration(getActivity(), R.drawable.divider));
recyclerView.setAdapter(...);
return rootView;
}
Также есть библиотека Лукаса Роча, которая должна упростить процесс украшения предметов. Хотя не пробовал.
Среди его функций :
- Коллекция художественных оформлений, включающих в себя:
- Расстояние между предметами Горизонтальные/вертикальные разделители.
- Элемент списка
Ответ 2
Просто добавь
recyclerView.addItemDecoration(new DividerItemDecoration(getContext(),
DividerItemDecoration.VERTICAL));
Также вам может понадобиться добавить зависимость
compile 'com.android.support:recyclerview-v7:27.1.0'
РЕДАКТИРОВАТЬ:
Чтобы немного его настроить, вы можете добавить собственный чертеж:
DividerItemDecoration itemDecorator = new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL);
itemDecorator.setDrawable(ContextCompat.getDrawable(getContext(), R.drawable.divider));
Вы можете использовать любой пользовательский формат, например:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/colorPrimary"/>
<size android:height="0.5dp"/>
</shape>
Ответ 3
Могу ли я обратить ваше внимание на этот конкретный файл на Github от Alex Fu:
https://gist.github.com/alexfu/0f464fc3742f134ccd1e
Это файл примера DividerItemDecoration.java "вытащил прямо из демонстраций поддержки". (https://plus.google.com/103498612790395592106/posts/VVEB3m7NkSS)
Мне удалось легко получить разделительные линии после импорта этого файла в мой проект и добавить его как украшение элемента в вид ресайклера.
Вот как выглядит мой onCreateView в моем фрагменте, содержащем Recyclerview:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_recycler_view, container, false);
mRecyclerView = (RecyclerView) rootView.findViewById(R.id.my_recycler_view);
mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST));
mRecyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
return rootView;
}
Я уверен, что дополнительный стиль можно сделать, но это отправная точка.:)
Ответ 4
Простая реализация ItemDecoration
для равных пробелов между всеми элементами.
public class SpacesItemDecoration extends RecyclerView.ItemDecoration {
private int space;
public SpacesItemDecoration(int space) {
this.space = space;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
outRect.left = space;
outRect.right = space;
outRect.bottom = space;
// Add top margin only for the first item to avoid double space between items
if(parent.getChildAdapterPosition(view) == 0) {
outRect.top = space;
}
}
}
Ответ 5
Простым является установка цвета фона для RecyclerView и другого цвета фона для элементов. Вот пример...
<android.support.v7.widget.RecyclerView
android:background="#ECEFF1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"/>
и TextView (это может быть что угодно) с нижним полем "x" dp или px.
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="1dp"
android:background="#FFFFFF"/>
Выход...
Ответ 6
Я думаю, что использование простого делителя поможет вам
Чтобы добавить разделитель к каждому элементу:
1- Добавьте это в выпадающий каталог 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="#999999" />
</shape>
2- Создать класс SimpleDividerItemDecoration
Я использовал этот пример для определения этого класса:
https://gist.github.com/polbins/e37206fbc444207c0e92
package com.example.myapp;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import com.example.myapp.R;
public class SimpleDividerItemDecoration extends RecyclerView.ItemDecoration{
private Drawable mDivider;
public SimpleDividerItemDecoration(Resources resources) {
mDivider = resources.getDrawable(R.drawable.line_divider);
}
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);
}
}
}
3- В активности или фрагменте, использующем RecyclerView, внутри onCreateView добавьте это:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
RecyclerView myRecyclerView = (RecyclerView) layout.findViewById(R.id.my_recycler_view);
myRecyclerView.addItemDecoration(new SimpleDividerItemDecoration(getResources()));
....
}
4- Чтобы добавить расстояние между элементами
вам просто нужно добавить свойство дополнения к виду вашего товара
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
android:padding="4dp"
>
..... item structure
</RelativeLayout>
Ответ 7
Как я установил ItemAnimators
. ItemDecorator
не входит и не выходит вместе с анимацией.
Я просто получил строку представления в файле макета представления каждого элемента. Это решило мой случай. DividerItemDecoration
казалось слишком большим колдовством для простого делителя.
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:background="@color/lt_gray"/>
Ответ 8
Это просто, вам не нужен такой сложный код
DividerItemDecoration divider = new
DividerItemDecoration(mRVMovieReview.getContext(),
DividerItemDecoration.VERTICAL);
divider.setDrawable(
ContextCompat.getDrawable(getBaseContext(), R.drawable.line_divider)
);
mRVMovieReview.addItemDecoration(divider);
Добавьте это в свой чертеж: 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:height="1dp" />
<solid android:color="@android:color/black" />
</shape>
Ответ 9
Поскольку нет правильного способа реализовать это, но с использованием Material Design, я просто сделал следующий трюк, чтобы добавить разделитель в элемент списка напрямую:
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/dividerColor"/>
Ответ 10
ОБНОВЛЕНИЕ ОКТЯБРЬ 2016
В библиотеке поддержки v25.0.0 наконец реализована стандартная реализация основных горизонтальных и вертикальных разделителей!
https://developer.android.com/reference/android/support/v7/widget/DividerItemDecoration.html
Ответ 11
Если кто-то хочет добавить, скажем, 10dp интервал между элементами, вы можете сделать это, установив drawable на DividerItemDecoration
:
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(
recyclerView.getContext(),
layoutManager.getOrientation()
);
dividerItemDecoration.setDrawable(
ContextCompat.getDrawable(getContext(), R.drawable.divider_10dp)
);
Где divider_10dp
- ресурс с возможностью рисования, содержащий:
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<size android:height="10dp"/>
<solid android:color="@android:color/transparent"/>
</shape>
Ответ 12
Для тех, кто ищет только пробелы между элементами в RecyclerView
, см. мой подход, в котором вы получаете равные промежутки между всеми элементами, за исключением первого и последнего элементов, где я дал большее дополнение. Я применяю только проставку влево/вправо в горизонтальном LayoutManager
и сверху/снизу в вертикальном LayoutManager
.
public class PaddingItemDecoration extends RecyclerView.ItemDecoration {
private int mPaddingPx;
private int mPaddingEdgesPx;
public PaddingItemDecoration(Activity activity) {
final Resources resources = activity.getResources();
mPaddingPx = (int) resources.getDimension(R.dimen.paddingItemDecorationDefault);
mPaddingEdgesPx = (int) resources.getDimension(R.dimen.paddingItemDecorationEdge);
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
final int itemPosition = parent.getChildAdapterPosition(view);
if (itemPosition == RecyclerView.NO_POSITION) {
return;
}
int orientation = getOrientation(parent);
final int itemCount = state.getItemCount();
int left = 0;
int top = 0;
int right = 0;
int bottom = 0;
/** HORIZONTAL */
if (orientation == LinearLayoutManager.HORIZONTAL) {
/** all positions */
left = mPaddingPx;
right = mPaddingPx;
/** first position */
if (itemPosition == 0) {
left += mPaddingEdgesPx;
}
/** last position */
else if (itemCount > 0 && itemPosition == itemCount - 1) {
right += mPaddingEdgesPx;
}
}
/** VERTICAL */
else {
/** all positions */
top = mPaddingPx;
bottom = mPaddingPx;
/** first position */
if (itemPosition == 0) {
top += mPaddingEdgesPx;
}
/** last position */
else if (itemCount > 0 && itemPosition == itemCount - 1) {
bottom += mPaddingEdgesPx;
}
}
if (!isReverseLayout(parent)) {
outRect.set(left, top, right, bottom);
} else {
outRect.set(right, bottom, left, top);
}
}
private boolean isReverseLayout(RecyclerView parent) {
if (parent.getLayoutManager() instanceof LinearLayoutManager) {
LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
return layoutManager.getReverseLayout();
} else {
throw new IllegalStateException("PaddingItemDecoration can only be used with a LinearLayoutManager.");
}
}
private int getOrientation(RecyclerView parent) {
if (parent.getLayoutManager() instanceof LinearLayoutManager) {
LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
return layoutManager.getOrientation();
} else {
throw new IllegalStateException("PaddingItemDecoration can only be used with a LinearLayoutManager.");
}
}
}
dimens.xml
<resources>
<dimen name="paddingItemDecorationDefault">10dp</dimen>
<dimen name="paddingItemDecorationEdge">20dp</dimen>
</resources>
Ответ 13
- Вот простой взлом для добавления разделителя
-
Просто добавьте фон в макет вашего элемента recycler следующим образом
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/shape_border"
android:gravity="center"
android:orientation="horizontal"
android:padding="5dp">
<ImageView
android:id="@+id/imageViewContactLogo"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginRight="10dp"
android:src="@drawable/ic_user" />
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.92"
android:gravity="center|start"
android:orientation="vertical">
<TextView
android:id="@+id/textViewContactName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="@+id/textViewStatusOrNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:singleLine="true"
android:text=""
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>
<TextView
android:id="@+id/textViewUnreadCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:padding="5dp"
android:text=""
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="@color/red"
android:textSize="22sp" />
<Button
android:id="@+id/buttonInvite"
android:layout_width="54dp"
android:layout_height="wrap_content"
android:background="@drawable/ic_add_friend" />
</LinearLayout>
Создайте следующий файл shape_border.xml в папке с рисунком
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<gradient
android:angle="270"
android:centerColor="@android:color/transparent"
android:centerX="0.01"
android:startColor="#000" />
</shape>
Вот окончательный результат - RecyclerView с делителем.
Ответ 14
Это фактически не решает проблему, но в качестве временного обходного пути вы можете установить свойство useCompatPadding на карте в своем XML-макете, чтобы сделать это измерьте то же, что и в версиях до Lollipop.
card_view:cardUseCompatPadding="true"
Ответ 15
Добавьте маржу к своему виду, это сработало для меня.
android:layout_marginTop="10dp"
Если вы просто хотите добавить равное расстояние и хотите сделать это в XML, просто установите padding
на RecyclerView
и равное количество layoutMargin
к элементу, который вы надуваете в свой RecyclerView
, и пусть цвет фона определяет цвет интервала.
Ответ 16
Я разветкил DividerItemDecoration из более старого стиля и упростил его, чтобы он соответствовал моему варианту использования, и я также изменил его, чтобы нарисовать разделители так, как они рисованы в ListView, включая разделитель после последнего элемента списка. Это также будет обрабатывать вертикальные анимации ItemAnimator:
1) Добавьте этот класс в свой проект:
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private static final int[] ATTRS = new int[]{android.R.attr.listDivider};
private Drawable divider;
public DividerItemDecoration(Context context) {
try {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
divider = a.getDrawable(0);
a.recycle();
} catch (Resources.NotFoundException e) {
// TODO Log or handle as necessary.
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
if (divider == null) return;
if (parent.getChildAdapterPosition(view) < 1) return;
if (getOrientation(parent) == LinearLayoutManager.VERTICAL)
outRect.top = divider.getIntrinsicHeight();
else
throw new IllegalArgumentException("Only usable with vertical lists");
}
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (divider == null) {
super.onDrawOver(c, parent, state);
return;
}
final int left = parent.getPaddingLeft();
final int right = parent.getWidth() - parent.getPaddingRight();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; ++i) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
final int size = divider.getIntrinsicHeight();
final int top = (int) (child.getTop() - params.topMargin - size + child.getTranslationY());
final int bottom = top + size;
divider.setBounds(left, top, right, bottom);
divider.draw(c);
if (i == childCount - 1) {
final int newTop = (int) (child.getBottom() + params.bottomMargin + child.getTranslationY());
final int newBottom = newTop + size;
divider.setBounds(left, newTop, right, newBottom);
divider.draw(c);
}
}
}
private int getOrientation(RecyclerView parent) {
if (!(parent.getLayoutManager() instanceof LinearLayoutManager))
throw new IllegalStateException("Layout manager must be an instance of LinearLayoutManager");
return ((LinearLayoutManager) parent.getLayoutManager()).getOrientation();
}
}
2) Добавьте декоратор в свой RecylerView:
recyclerView.addItemDecoration(new DividerItemDecoration(getActivity()));
Ответ 17
В результате поиска google добавьте этот ItemDecoration в свой RecyclerView
:
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private Drawable mDivider;
private boolean mShowFirstDivider = false;
private boolean mShowLastDivider = false;
public DividerItemDecoration(Context context, AttributeSet attrs) {
final TypedArray a = context
.obtainStyledAttributes(attrs, new int[]{android.R.attr.listDivider});
mDivider = a.getDrawable(0);
a.recycle();
}
public DividerItemDecoration(Context context, AttributeSet attrs, boolean showFirstDivider,
boolean showLastDivider) {
this(context, attrs);
mShowFirstDivider = showFirstDivider;
mShowLastDivider = showLastDivider;
}
public DividerItemDecoration(Drawable divider) {
mDivider = divider;
}
public DividerItemDecoration(Drawable divider, boolean showFirstDivider,
boolean showLastDivider) {
this(divider);
mShowFirstDivider = showFirstDivider;
mShowLastDivider = showLastDivider;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
if (mDivider == null) {
return;
}
if (parent.getChildPosition(view) < 1) {
return;
}
if (getOrientation(parent) == LinearLayoutManager.VERTICAL) {
outRect.top = mDivider.getIntrinsicHeight();
} else {
outRect.left = mDivider.getIntrinsicWidth();
}
}
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (mDivider == null) {
super.onDrawOver(c, parent, state);
return;
}
// Initialization needed to avoid compiler warning
int left = 0, right = 0, top = 0, bottom = 0, size;
int orientation = getOrientation(parent);
int childCount = parent.getChildCount();
if (orientation == LinearLayoutManager.VERTICAL) {
size = mDivider.getIntrinsicHeight();
left = parent.getPaddingLeft();
right = parent.getWidth() - parent.getPaddingRight();
} else { //horizontal
size = mDivider.getIntrinsicWidth();
top = parent.getPaddingTop();
bottom = parent.getHeight() - parent.getPaddingBottom();
}
for (int i = mShowFirstDivider ? 0 : 1; i < childCount; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
if (orientation == LinearLayoutManager.VERTICAL) {
top = child.getTop() - params.topMargin;
bottom = top + size;
} else { //horizontal
left = child.getLeft() - params.leftMargin;
right = left + size;
}
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
// show last divider
if (mShowLastDivider && childCount > 0) {
View child = parent.getChildAt(childCount - 1);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
if (orientation == LinearLayoutManager.VERTICAL) {
top = child.getBottom() + params.bottomMargin;
bottom = top + size;
} else { // horizontal
left = child.getRight() + params.rightMargin;
right = left + size;
}
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
private int getOrientation(RecyclerView parent) {
if (parent.getLayoutManager() instanceof LinearLayoutManager) {
LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
return layoutManager.getOrientation();
} else {
throw new IllegalStateException(
"DividerItemDecoration can only be used with a LinearLayoutManager.");
}
}
}
Ответ 18
Эта ссылка работала как шарм для меня:
https://gist.github.com/lapastillaroja/858caf1a82791b6c1a36
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.View;
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private Drawable mDivider;
private boolean mShowFirstDivider = false;
private boolean mShowLastDivider = false;
public DividerItemDecoration(Context context, AttributeSet attrs) {
final TypedArray a = context
.obtainStyledAttributes(attrs, new int[]{android.R.attr.listDivider});
mDivider = a.getDrawable(0);
a.recycle();
}
public DividerItemDecoration(Context context, AttributeSet attrs, boolean showFirstDivider,
boolean showLastDivider) {
this(context, attrs);
mShowFirstDivider = showFirstDivider;
mShowLastDivider = showLastDivider;
}
public DividerItemDecoration(Drawable divider) {
mDivider = divider;
}
public DividerItemDecoration(Drawable divider, boolean showFirstDivider,
boolean showLastDivider) {
this(divider);
mShowFirstDivider = showFirstDivider;
mShowLastDivider = showLastDivider;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
if (mDivider == null) {
return;
}
if (parent.getChildPosition(view) < 1) {
return;
}
if (getOrientation(parent) == LinearLayoutManager.VERTICAL) {
outRect.top = mDivider.getIntrinsicHeight();
} else {
outRect.left = mDivider.getIntrinsicWidth();
}
}
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (mDivider == null) {
super.onDrawOver(c, parent, state);
return;
}
// Initialization needed to avoid compiler warning
int left = 0, right = 0, top = 0, bottom = 0, size;
int orientation = getOrientation(parent);
int childCount = parent.getChildCount();
if (orientation == LinearLayoutManager.VERTICAL) {
size = mDivider.getIntrinsicHeight();
left = parent.getPaddingLeft();
right = parent.getWidth() - parent.getPaddingRight();
} else { //horizontal
size = mDivider.getIntrinsicWidth();
top = parent.getPaddingTop();
bottom = parent.getHeight() - parent.getPaddingBottom();
}
for (int i = mShowFirstDivider ? 0 : 1; i < childCount; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
if (orientation == LinearLayoutManager.VERTICAL) {
top = child.getTop() - params.topMargin;
bottom = top + size;
} else { //horizontal
left = child.getLeft() - params.leftMargin;
right = left + size;
}
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
// show last divider
if (mShowLastDivider && childCount > 0) {
View child = parent.getChildAt(childCount - 1);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
if (orientation == LinearLayoutManager.VERTICAL) {
top = child.getBottom() + params.bottomMargin;
bottom = top + size;
} else { // horizontal
left = child.getRight() + params.rightMargin;
right = left + size;
}
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
private int getOrientation(RecyclerView parent) {
if (parent.getLayoutManager() instanceof LinearLayoutManager) {
LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
return layoutManager.getOrientation();
} else {
throw new IllegalStateException(
"DividerItemDecoration can only be used with a LinearLayoutManager.");
}
}
}
Тогда в вашей деятельности:
mCategoryRecyclerView.addItemDecoration(
new DividerItemDecoration(this, null));
Или это, если вы используете фрагмент:
mCategoryRecyclerView.addItemDecoration(
new DividerItemDecoration(getActivity(), null));
Ответ 19
Мы можем украсить предметы, используя различные декораторы, прикрепленные к recyclerview, такие как DividerItemDecoration:
Просто используйте следующее... взятое из ответа EyesClear
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private static final int[] ATTRS = new int[]{android.R.attr.listDivider};
private Drawable mDivider;
/**
* Default divider will be used
*/
public DividerItemDecoration(Context context) {
final TypedArray styledAttributes = context.obtainStyledAttributes(ATTRS);
mDivider = styledAttributes.getDrawable(0);
styledAttributes.recycle();
}
/**
* Custom divider will be used
*/
public DividerItemDecoration(Context context, int resId) {
mDivider = ContextCompat.getDrawable(context, resId);
}
@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; 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);
}
}
}
и затем используйте приведенное выше значение
RecyclerView.ItemDecoration itemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST);
recyclerView.addItemDecoration(itemDecoration);
Здесь будут отображаться разделители между каждым элементом в списке, как показано ниже:
И для тех, кто ищет более подробную информацию, вы можете проверить это руководство Использование RecyclerView _ CodePath Android Cliffnotes
В некоторых ответах здесь предлагается использовать поля, но это означает, что:
Если вы добавите верхний и нижний поля, они будут отображаться как добавленные между элементами, так и они будут слишком большими. Если вы добавите только один из них, то не будет никакого поля в верхней или нижней части всего списка. Если вы добавите половину расстояния вверху, наполовину внизу, внешние поля будут слишком маленькими.
Таким образом, единственным эстетически правильным решением является разделитель, который система знает, где правильно применять: между элементами, но не выше или ниже элементов.
Пожалуйста, дайте мне знать о любых сомнениях в комментариях ниже:)
Ответ 20
Слишком поздно, но для GridLayoutManager
Я использую это:
public class GridSpacesItemDecoration : RecyclerView.ItemDecoration
{
private int space;
public GridSpacesItemDecoration(int space) {
this.space = space;
}
public override void GetItemOffsets(Android.Graphics.Rect outRect, View view, RecyclerView parent, RecyclerView.State state)
{
var position = parent.GetChildLayoutPosition(view);
/// Only for GridLayoutManager Layouts
var manager = parent.GetLayoutManager() as GridLayoutManager;
if (parent.GetChildLayoutPosition(view) < manager.SpanCount)
outRect.Top = space;
if (position % 2 != 0) {
outRect.Right = space;
}
outRect.Left = space;
outRect.Bottom = space;
}
}
Эта работа для любого количества периодов, которое у вас есть.
Олли.
Ответ 21
Вы можете добавить с программно легко.
Если ваш Layout Manager - Linearlayout, вы можете использовать:
DividerItemDecoration является RecyclerView.ItemDecoration, который может быть используется в качестве разделителя между элементами LinearLayoutManager. Поддерживает как ГОРИЗОНТАЛЬНАЯ, так и ВЕРТИКАЛЬНАЯ ориентации.
mDividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
mLayoutManager.getOrientation());
recyclerView.addItemDecoration(mDividerItemDecoration);
источник
Ответ 22
Вместо создания shape xml
для изменения высоты и цвета разделителя. Вы можете создать программно как
val divider = DividerItemDecoration(context,
DividerItemDecoration.VERTICAL)
divider.setDrawable(ShapeDrawable().apply {
intrinsicHeight = resources.getDimensionPixelOffset(R.dimen.dp_15)
paint.color = Color.RED // note: currently (support version 28.0.0), we can not use tranparent color here, if we use transparent, we still see a small divider line. So if we want to display transparent space, we can set color = background color or we can create a custom ItemDecoration instead of DividerItemDecoration.
})
recycler_devices.addItemDecoration(divider)
Ответ 23
Если вы хотите добавить одно и то же пространство для элементов, самым простым способом является добавление верхних + левых дополнений для RecycleView и правого и нижнего полей к элементам карты.
dimens.xml
<resources>
<dimen name="divider">1dp</dimen>
</resources>
list_item.xml
<CardView
android:layout_marginBottom="@dimen/divider"
android:layout_marginRight="@dimen/divider">
...
</CardView>
list.xml
<RecyclerView
android:paddingLeft="@dimen/divider"
android:paddingTop="@dimen/divider"
/>
Ответ 24
Я добавил строку в элемент списка, как показано ниже
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/dividerColor"/>
1px будет рисовать тонкую линию.
Если вы хотите скрыть разделитель для последней строки, тогда divider.setVisiblity(View.GONE);
в onBindViewHolder для последнего элемента списка.
Ответ 25
Мне кажется, что нужен простой ответ на основе кода, не использующий XML
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL);
ShapeDrawable shapeDrawableForDivider = new ShapeDrawable(new RectShape());
int dividerThickness = // (int) (SomeOtherView.getHeight() * desiredPercent);
shapeDrawableForDivider.setIntrinsicHeight(dividerThickness);
shapeDrawableForDivider.setAlpha(0);
dividerItemDecoration.setDrawable(shapeDrawableForDivider);
recyclerView.addItemDecoration(dividerItemDecoration);
Ответ 26
RecyclerView
немного отличается от ListView
. На самом деле, RecyclerView
нуждается в подобной структуре ListView
. Например, a LinearLayout
. LinearLayout
имеет параметры для деления каждого элемента.
В приведенном ниже коде есть RecyclerView
, состоящий из CardView
объектов в пределах LinearLayout
с "отступом", который помещает некоторое пространство между элементами. Сделайте это пространство очень маленьким, и вы получите строку.
Здесь вид Recycler в recyclerview_layout.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:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".ToDoList">
<!-- A RecyclerView with some commonly used attributes -->
<android.support.v7.widget.RecyclerView
android:id="@+id/todo_recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
И вот как выглядит каждый элемент (и он отображается как разделенный из-за андроида: добавление в LinearLayout, которое окружает все.) в другом файле: cards_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
**android:padding="@dimen/activity_vertical_margin"**>
<!-- A CardView that contains a TextView -->
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/card_view"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="100dp"
android:elevation="30dp"
card_view:cardElevation="3dp">
<TextView
android:id="@+id/info_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</android.support.v7.widget.CardView>
</LinearLayout>
Ответ 27
Очень простое решение - использовать RecyclerView-FlexibleDivider
Добавить зависимость:
compile 'com.yqritc:recyclerview-flexibledivider:1.4.0'
Добавьте к вашему recyclerview:
recyclerView.addItemDecoration(new HorizontalDividerItemDecoration.Builder(context).build());
И все готово!
Ответ 28
1. Один из способов с помощью просмотра карт и ресайклеров вместе мы можем легко добавить эффект как разделитель.
например https://developer.android.com/training/material/lists-cards.html
2. и другие - добавление в качестве разделителя в list_item_layout просмотра recycler.
<View
android:id="@+id/view1"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/colorAccent" />
Ответ 29
public class CommonItemSpaceDecoration extends RecyclerView.ItemDecoration {
private int mSpace = 0;
private boolean mVerticalOrientation = true;
public CommonItemSpaceDecoration(int space) {
this.mSpace = space;
}
public CommonItemSpaceDecoration(int space, boolean verticalOrientation) {
this.mSpace = space;
this.mVerticalOrientation = verticalOrientation;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
outRect.top = SizeUtils.dp2px(view.getContext(), mSpace);
if (mVerticalOrientation) {
if (parent.getChildAdapterPosition(view) == 0) {
outRect.set(0, SizeUtils.dp2px(view.getContext(), mSpace), 0, SizeUtils.dp2px(view.getContext(), mSpace));
} else {
outRect.set(0, 0, 0, SizeUtils.dp2px(view.getContext(), mSpace));
}
} else {
if (parent.getChildAdapterPosition(view) == 0) {
outRect.set(SizeUtils.dp2px(view.getContext(), mSpace), 0, 0, 0);
} else {
outRect.set(SizeUtils.dp2px(view.getContext(), mSpace), 0, SizeUtils.dp2px(view.getContext(), mSpace), 0);
}
}
}
}
Это добавит пространство в каждый элемент вверху и внизу (или влево и вправо). Затем вы можете установить его в recyclerView.
recyclerView.addItemDecoration(new CommonItemSpaceDecoration(16));
SizeUtils.java
public class SizeUtils {
public static int dp2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
Ответ 30
Реализовать свою собственную версию RecyclerView.ItemDecoration
public class SpacingItemDecoration extends RecyclerView.ItemDecoration {
private int spacingPx;
private boolean addStartSpacing;
private boolean addEndSpacing;
public SpacingItemDecoration(int spacingPx) {
this(spacingPx, false, false);
}
public SpacingItemDecoration(int spacingPx, boolean addStartSpacing, boolean addEndSpacing) {
this.spacingPx = spacingPx;
this.addStartSpacing = addStartSpacing;
this.addEndSpacing = addEndSpacing;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
if (spacingPx <= 0) {
return;
}
if (addStartSpacing && parent.getChildLayoutPosition(view) < 1 || parent.getChildLayoutPosition(view) >= 1) {
if (getOrientation(parent) == LinearLayoutManager.VERTICAL) {
outRect.top = spacingPx;
} else {
outRect.left = spacingPx;
}
}
if (addEndSpacing && parent.getChildAdapterPosition(view) == getTotalItemCount(parent) - 1) {
if (getOrientation(parent) == LinearLayoutManager.VERTICAL) {
outRect.bottom = spacingPx;
} else {
outRect.right = spacingPx;
}
}
}
private int getTotalItemCount(RecyclerView parent) {
return parent.getAdapter().getItemCount();
}
private int getOrientation(RecyclerView parent) {
if (parent.getLayoutManager() instanceof LinearLayoutManager) {
return ((LinearLayoutManager) parent.getLayoutManager()).getOrientation();
} else {
throw new IllegalStateException("SpacingItemDecoration can only be used with a LinearLayoutManager.");
}
}
}