这是以前在 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"/>
在这种情况下,是否可以定义边距和/或将自定义分隔线视图直接添加到列表项的布局中,还是有更好的方法来实现我的目标?
com.homeretailgroup.argos.android.view.decorators.DividerItemDecoration
中有一个类并像这样使用它:mRecyclerView.addItemDecoration(new DividerItemDecoration(activity, LinearLayoutManager.VERTICAL));
2016 年 10 月更新
Android 支持库 25.0.0 版引入了 DividerItemDecoration
类:
DividerItemDecoration 是一个 RecyclerView.ItemDecoration,可用作 LinearLayoutManager 的项目之间的分隔符。它支持水平和垂直方向。
用法:
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
layoutManager.getOrientation());
recyclerView.addItemDecoration(dividerItemDecoration);
上一个答案
有些答案要么使用已被弃用的方法,要么没有给出完整的解决方案,所以我尝试做一个简短的、最新的总结。
与 ListView
不同,RecyclerView
类没有任何与分隔符相关的参数。相反,您需要扩展 ItemDecoration
,即 RecyclerView
的内部类:
ItemDecoration 允许应用程序向适配器数据集中的特定项目视图添加特殊的绘图和布局偏移。这对于在项目、突出显示、视觉分组边界等之间绘制分隔线很有用。所有 ItemDecoration 都按照它们添加的顺序绘制,在项目视图之前(在 onDraw() 中)和在项目之后(在 onDrawOver(Canvas, RecyclerView, RecyclerView.State) 中。
垂直间距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
并覆盖 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/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="#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;
}
还有 Lucas Rocha's library 应该简化项目装饰过程。我还没有尝试过。
它的 features 包括:
库存物品装饰品的集合,包括:
项目间距水平/垂直分隔线。
项目清单
只需添加
recyclerView.addItemDecoration(new DividerItemDecoration(getContext(),
DividerItemDecoration.VERTICAL));
此外,您可能需要添加依赖项
implementation 'com.android.support:recyclerview-v7:28.0.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>
Configuration
作为垂直分隔符:if (orientation == Configuration.ORIENTATION_LANDSCAPE) { recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.HORIZONTAL)); } else { recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));}
能否请您注意 Alex Fu 在 GitHub 上的这个特定文件: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));
mRecyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
return rootView;
}
我确信可以做额外的样式,但这是一个起点。 :)
一个简单的 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;
}
}
}
getChildPosition
现在已弃用,可以改用 getChildAdapterPosition
。
super.getItemOffsets
的调用,否则您的偏移量将被覆盖。
getChildLayoutPosition
吗?
一种简单的方法是为 RecyclerView 设置背景颜色,并为项目设置不同的背景颜色。这是一个例子......
<android.support.v7.widget.RecyclerView
android:background="#ECEFF1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"/>
以及底部边距为“x”dp 或 px 的 TextView 项目(尽管它可以是任何东西)。
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="1dp"
android:background="#FFFFFF"/>
输出...
https://i.stack.imgur.com/hNJFG.png
这很简单,你不需要这么复杂的代码:
DividerItemDecoration divider =
new DividerItemDecoration(mRVMovieReview.getContext(),
DividerItemDecoration.VERTICAL);
divider.setDrawable(ContextCompat.getDrawable(getBaseContext(),
R.drawable.line_divider));
mRVMovieReview.addItemDecoration(divider);
在你的drawable中添加这个: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>
我处理 Divider 视图和 Divider Insets 的方式是添加 RecyclerView 扩展。
1.
通过命名 View 或 RecyclerView 添加新的扩展文件:
RecyclerViewExtension.kt
并在 RecyclerViewExtension.kt 文件中添加 setDivider
扩展方法。
/*
* 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
包内创建一个可绘制资源文件,如 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
的左右 margin。
3.
在初始化 RecyclerView 的 Activity 或 Fragment 上,您可以通过调用设置自定义可绘制对象:
recyclerView.setDivider(R.drawable.recycler_view_divider)
4.
干杯🍺
https://i.stack.imgur.com/jStGN.png
正如我设置的 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"/>
我认为使用一个简单的分隔线会帮助你
为每个项目添加分隔符:
1.将这个添加到drawable目录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 的 Activity 或 Fragment 中,在 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.添加Item之间的间距
您只需要将填充属性添加到您的项目视图
<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>
如果有人只想在项目之间添加 10 dp 间距,您可以通过将 drawable 设置为 DividerItemDecoration
来实现:
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(
recyclerView.getContext(),
layoutManager.getOrientation()
);
dividerItemDecoration.setDrawable(
ContextCompat.getDrawable(getContext(), R.drawable.divider_10dp)
);
recyclerView.addItemDecoration(dividerItemDecoration);
其中 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>
由于没有正确的方法来正确使用 Material Design 来实现这一点,我只是做了以下技巧来直接在列表项上添加一个分隔符:
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/dividerColor"/>
您可以通过编程方式创建它,而不是创建用于更改分隔线高度和颜色的 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)
为您的视图添加边距。它对我有用。
android:layout_marginTop="10dp"
如果您只想添加 等间距 并希望在 XML 中添加,只需将 padding
设置为您的 RecyclerView
并将等量的 layoutMargin
设置为项目你充气到你的 RecyclerView
,让背景颜色决定间距颜色。
RecyclerView
时,拉到列表末尾时的 overscroll
效果将应用不必要的填充
<?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:card_view="http://schemas.android.com/apk/res-auto" android:id="@+id/card_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="10dp" card_view:cardElevation="4dp" <!-- your item's XML here --> </android.support.v7.widget.CardView>
对于那些仅在 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.");
}
}
}
文件尺寸.xml
<resources>
<dimen name="paddingItemDecorationDefault">10dp</dimen>
<dimen name="paddingItemDecorationEdge">20dp</dimen>
</resources>
这是添加分隔线的简单技巧
只需为您的回收站项目的布局添加一个背景,如下所示
在 drawable 文件夹中创建以下 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。
https://i.stack.imgur.com/lKntv.png
parent.getChildAdapterPosition(view) != parent.getAdapter().getItemCount() - 1
可能应该是 parent.getChildAdapterPosition(view) > 0
而 outRect.bottom = mVerticalSpaceHeight
变成 outRect.top = mVerticalSpaceHeight
它应该是公认的答案。
这实际上并不能解决问题,但作为一种临时解决方法,您可以在 XML 布局中设置卡片上的 useCompatPadding 属性,使其测量值与在 Lollipop 之前的版本上相同。
card_view:cardUseCompatPadding="true"
我将 DividerItemDecoration 从一个较旧的 gist 中分叉出来,并对其进行了简化以适合我的用例,并且我还对其进行了修改,以按照在 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()));
我觉得需要一个不使用 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);
我非常喜欢这个答案,我用单表达式 Kotlin 答案重写了它:
recyclerView.addItemDecoration(DividerItemDecoration(this,DividerItemDecoration.VERTICAL).also { deco ->
with (ShapeDrawable(RectShape())){
intrinsicHeight = (resources.displayMetrics.density * 24).toInt()
alpha = 0
deco.setDrawable(this)
}
})
这与@Nerdy 的原始答案相同,只是它将分隔线的高度设置为 24dp 而不是另一个视图高度的百分比。
这是一个装饰,可让您设置项目之间的间距以及边缘的间距。这适用于 HORIZONTAL
和 VERTICAL
布局。
class LinearSpacingDecoration(
@Px private val itemSpacing: Int,
@Px private val edgeSpacing: Int = 0
): RecyclerView.ItemDecoration() {
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
val count = parent.adapter?.itemCount ?: 0
val position = parent.getChildAdapterPosition(view)
val leading = if (position == 0) edgeSpacing else itemSpacing
val trailing = if (position == count - 1) edgeSpacing else 0
outRect.run {
if ((parent.layoutManager as? LinearLayoutManager)?.orientation == LinearLayout.VERTICAL) {
top = leading
bottom = trailing
} else {
left = leading
right = trailing
}
}
}
}
用法:
recyclerView.addItemDecoration(LinearSpacingDecoration(itemSpacing = 10, edgeSpacing = 20))
取自 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 the 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 { // hHorizontal
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.");
}
}
}
这个链接对我来说就像一个魅力:
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));
mShowFirstDivider = false
、mShowLastDivider = true
,但它不起作用。知道为什么吗?
我们可以使用附加到 recyclerview 的各种装饰器来装饰项目,例如 DividerItemDecoration:
只需使用以下...取自 the answer byEyesClear:
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);
这将在列表中的每个项目之间显示分隔符,如下所示:
https://i.stack.imgur.com/06d1F.png
对于那些正在寻找更多详细信息的人,可以查看本指南 Using the RecyclerView _ CodePath Android Cliffnotes。
这里的一些答案建议使用边距,但问题是:
如果同时添加上边距和下边距,它们会出现在项目之间,并且它们会太大。如果只添加其中一个,则整个列表的顶部或底部都没有边距。如果在顶部添加一半距离,在底部添加一半,则外边距会太小。
因此,唯一美学上正确的解决方案是系统知道在哪里正确应用的分隔符:在项目之间,而不是在项目之上或之下。
DividerItemDecoration
代码的外观。
如果要为项目添加相同的空间,最简单的方法是为 RecycleView 添加顶部+左填充和为卡片项添加右+底部边距。
文件尺寸.xml
<resources>
<dimen name="divider">1dp</dimen>
</resources>
文件 list_item.xml
<CardView
android:layout_marginBottom="@dimen/divider"
android:layout_marginRight="@dimen/divider">
...
</CardView>
文件列表.xml
<RecyclerView
android:paddingLeft="@dimen/divider"
android:paddingTop="@dimen/divider"
/>
对于 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;
}
}
这适用于您拥有的任何跨度计数。
FlexboxLayoutManager
?
您可以轻松地以编程方式添加它。
如果您的布局管理器是线性布局,那么您可以使用:
DividerItemDecoration 是一个 RecyclerView.ItemDecoration,可用作 LinearLayoutManager 的项目之间的分隔符。它支持水平和垂直方向。
mDividerItemDecoration =
new DividerItemDecoration(recyclerView.getContext(),
mLayoutManager.getOrientation());
recyclerView.addItemDecoration(mDividerItemDecoration);
为了在 RecylerView 中实现项目之间的间距,我们可以使用 ItemDecorators:
addItemDecoration(object : RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State,
) {
super.getItemOffsets(outRect, view, parent, state)
if (parent.getChildAdapterPosition(view) > 0) {
outRect.top = 8.dp // Change this value with anything you want. Remember that you need to convert integers to pixels if you are working with dps :)
}
}
})
考虑到我粘贴的代码,有几点需要考虑:
你真的不需要调用 super.getItemOffsets 但我选择了,因为我想扩展基类定义的行为。如果库有更新在幕后做更多的逻辑,我们会错过它。
作为向 Rect 添加顶部间距的替代方法,您还可以添加底部间距,但是与获取适配器的最后一项相关的逻辑更复杂,因此这可能会稍微好一些。
我使用扩展属性将简单整数转换为 dps:8.dp。像这样的东西可能会起作用:
val Int.dp: Int
get() = (this * Resources.getSystem().displayMetrics.density + 0.5f).toInt()
// Extension function works too, but invoking it would become something like 8.dp()
我在列表项中添加了一行,如下所示:
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/dividerColor"/>
“1px”将画出细线。
如果要隐藏最后一行的分隔符,请在 onBindViewHolder 上为最后一个列表项使用 divider.setVisiblity(View.GONE);
。
其中一种方法是同时使用 cardview 和 recycler 视图。我们可以轻松添加效果,例如分隔线。示例:使用 RecyclerView 创建动态列表 另一种方法是将视图作为分隔符添加到回收器视图的 list_item_layout 中。 <查看 android:id="@+id/view1" android:layout_width="match_parent" android:layout_height="1dp" android:background="@color/colorAccent" />
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));
文件大小Utils.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);
}
}
onDraw()
中创建任何对象。我只是引用已经存在的实例。onDrawOver
中调用canvas.drawLine(startX, startY, stopX, stopY, mPaint)
吗?有什么性能差异吗?