我有一个非常简单的RecyclerView。 这就是我设置分隔符的方法
DividerItemDecoration itemDecorator = new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL);
itemDecorator.setDrawable(ContextCompat.getDrawable(getActivity(), R.drawable.news_divider));
recyclerView.addItemDecoration(itemDecorator);
这是drawable / news_divider.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<solid android:color="@color/white_two"/>
<size android:height="1dp"/>
</shape>
问题是由于一些愚蠢的原因,分隔符不仅仅是在项目之间创建的。但也是在最后一项之后。而且我只想在不是每个项目之后的项目之间。
知道如何防止分隔符出现在最后一项之后吗?
干杯谢谢
答案 0 :(得分:52)
尝试使用此代码,它不会显示最后一项的分隔符。
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 - 2; 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);
}
}
}
<强> divider.xml:强>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<size
android:width="1dp"
android:height="1dp" />
<solid android:color="@color/grey_300" />
</shape>
将分隔符设置为:
RecyclerView.ItemDecoration dividerItemDecoration = new DividerItemDecorator(ContextCompat.getDrawable(context, R.drawable.divider));
recyclerView.addItemDecoration(dividerItemDecoration);
答案 1 :(得分:32)
建议here你可以像这样扩展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);
}
}
}
);
<强> [UPDATE] 强>
@Rebecca Hsieh指出:
当RecyclerView中的项目视图没有透明背景时,此有效,例如,
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="#ffffff">
...
</LinearLayout>
RecyclerItemDecoration.getItemOffsets由RecyclerView调用以测量子位置。此解决方案将最后一个分隔符放在最后一个项目后面。因此,RecyclerView中的项目视图应该有一个背景来覆盖最后一个分隔符,这使它看起来像隐藏。
其他解决方案
如果你不喜欢被分开的分隔符,你可以简单地复制或扩展DividerItemDecoration类并通过将for (int i = 0; i < childCount; i++)
修改为for (int i = 0; i < childCount - 1; i++)
来改变其绘图行为
答案 2 :(得分:5)
接受的答案并没有为装饰分配空间,因为它没有覆盖getItemOffsets()
我调整了支持库中的DividerItemDecoration,以排除最后一项的装饰
public class DividerItemDecorator extends RecyclerView.ItemDecoration {
private Drawable mDivider;
private final Rect mBounds = new Rect();
public DividerItemDecorator(Drawable divider) {
mDivider = divider;
}
@Override
public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
canvas.save();
final int left;
final int right;
if (parent.getClipToPadding()) {
left = parent.getPaddingLeft();
right = parent.getWidth() - parent.getPaddingRight();
canvas.clipRect(left, parent.getPaddingTop(), right,
parent.getHeight() - parent.getPaddingBottom());
} else {
left = 0;
right = parent.getWidth();
}
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount - 1; i++) {
final View child = parent.getChildAt(i);
parent.getDecoratedBoundsWithMargins(child, mBounds);
final int bottom = mBounds.bottom + Math.round(child.getTranslationY());
final int top = bottom - mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(canvas);
}
canvas.restore();
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (parent.getChildAdapterPosition(view) == state.getItemCount() - 1) {
outRect.setEmpty();
} else
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
}
}
要应用装饰器,请使用
RecyclerView.ItemDecoration dividerItemDecoration = new DividerItemDecorator(dividerDrawable);
recyclerView.addItemDecoration(dividerItemDecoration);
可以在此处找到包含方向的来源 https://gist.github.com/abdulalin/146f8ca42aa8322692b15663b8d508ff
答案 3 :(得分:5)
这是 接受的答案 的Kotlin版本:
class DividerItemDecorator(private val divider: Drawable?) : RecyclerView.ItemDecoration() {
override fun onDrawOver(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) {
val dividerLeft = parent.paddingLeft
val dividerRight = parent.width - parent.paddingRight
val childCount = parent.childCount
for (i in 0..childCount - 2) {
val child: View = parent.getChildAt(i)
val params =
child.layoutParams as RecyclerView.LayoutParams
val dividerTop: Int = child.bottom + params.bottomMargin
val dividerBottom = dividerTop + (divider?.intrinsicHeight?:0)
divider?.setBounds(dividerLeft, dividerTop, dividerRight, dividerBottom)
divider?.draw(canvas)
}
}
}
答案 4 :(得分:3)
Kotlin的扩展功能:
fun RecyclerView.addItemDecorationWithoutLastDivider() {
if (layoutManager !is LinearLayoutManager)
return
addItemDecoration(object :
DividerItemDecoration(context, (layoutManager as LinearLayoutManager).orientation) {
override fun getItemOffsets( outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
super.getItemOffsets(outRect, view, parent, state)
if (parent.getChildAdapterPosition(view) == state.itemCount - 1)
outRect.setEmpty()
else
super.getItemOffsets(outRect, view, parent, state)
}
})
}
您可以轻松使用它:
recyclerView.addItemDecorationWithoutLastDivider()
答案 5 :(得分:2)
创建自己的Divider类(Example here)
在绘制分隔符的代码中,首先检查是否为列表中的最后一项绘制分隔符。如果是这样,请不要画画。
请注意,如果您覆盖OnDrawOver
,则会在您的视图的顶部绘制,包括滚动条等。最好坚持OnDraw
。 Google上有很多例子,但this是一个关于创建自己的装饰器的好教程。
答案 6 :(得分:2)
以下是我在我的应用中使用的DividerDecorator
类,它删除了最后一项的底线。
public class DividerDecorator extends RecyclerView.ItemDecoration {
private Drawable mDivider;
public DividerDecorator(Context context) {
mDivider = context.getResources().getDrawable(R.drawable.recyclerview_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);
}
}
}
您可以使用以下代码将其设置为RecyclerView
:
mRecyclerViewEvent.addItemDecoration(new DividerDecorator(context));
这是recyclerview_divider.xml
<size
android:width="1dp"
android:height="1dp" />
<solid android:color="@color/DividerColor" />
答案 7 :(得分:1)
这是Android支持DividerItemDecoration
的自定义版本,忽略了最后一项:
https://gist.github.com/mohsenoid/8ffdfa53f0465533833b0b44257aa641
主要区别是:
private fun drawVertical(canvas: Canvas, parent: RecyclerView) {
canvas.save()
val left: Int
val right: Int
if (parent.clipToPadding) {
left = parent.paddingLeft
right = parent.width - parent.paddingRight
canvas.clipRect(left, parent.paddingTop, right,
parent.height - parent.paddingBottom)
} else {
left = 0
right = parent.width
}
val childCount = parent.childCount
for (i in 0 until childCount - 1) {
val child = parent.getChildAt(i)
parent.getDecoratedBoundsWithMargins(child, mBounds)
val bottom = mBounds.bottom + Math.round(child.translationY)
val top = bottom - mDivider!!.intrinsicHeight
mDivider!!.setBounds(left, top, right, bottom)
mDivider!!.draw(canvas)
}
canvas.restore()
}
private fun drawHorizontal(canvas: Canvas, parent: RecyclerView) {
canvas.save()
val top: Int
val bottom: Int
if (parent.clipToPadding) {
top = parent.paddingTop
bottom = parent.height - parent.paddingBottom
canvas.clipRect(parent.paddingLeft, top,
parent.width - parent.paddingRight, bottom)
} else {
top = 0
bottom = parent.height
}
val childCount = parent.childCount
for (i in 0 until childCount - 1) {
val child = parent.getChildAt(i)
parent.layoutManager.getDecoratedBoundsWithMargins(child, mBounds)
val right = mBounds.right + Math.round(child.translationX)
val left = right - mDivider!!.intrinsicWidth
mDivider!!.setBounds(left, top, right, bottom)
mDivider!!.draw(canvas)
}
canvas.restore()
}
答案 8 :(得分:0)
Kotlin 版本和 使用 AbdulAli 的工作答案的原始 DividerItemDecorator 类的新签名函数进行更新:
class DividerItemDecorator(private val mDivider: Drawable) : ItemDecoration() {
private val mBounds: Rect = Rect()
override fun onDraw(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) {
canvas.save()
val left: Int
val right: Int
if (parent.clipToPadding) {
left = parent.paddingLeft
right = parent.width - parent.paddingRight
canvas.clipRect(
left, parent.paddingTop, right,
parent.height - parent.paddingBottom
)
} else {
left = 0
right = parent.width
}
val childCount = parent.childCount
for (i in 0 until childCount - 1) {
val child: View = parent.getChildAt(i)
parent.getDecoratedBoundsWithMargins(child, mBounds)
val bottom: Int = mBounds.bottom + Math.round(child.getTranslationY())
val top = bottom - mDivider.intrinsicHeight
mDivider.setBounds(left, top, right, bottom)
mDivider.draw(canvas)
}
canvas.restore()
}
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
if (parent.getChildAdapterPosition(view) == state.itemCount - 1) {
outRect.setEmpty()
} else outRect.set(0, 0, 0, mDivider.intrinsicHeight)
}
}
答案 9 :(得分:-2)
如果您已经使用以下设置:
DividerItemDecoration dividerItemDecoration;
dividerItemDecoration = new DividerItemDecoration(context,
DividerItemDecoration.VERTICAL);
mRecyclerView.addItemDecoration(dividerItemDecoration);
,如果要删除:
mRecyclerView.removeItemDecoration(dividerItemDecoration);