这是之前在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 itemdecoration -一个基本的分隔符样本在Kotlin android

一个完整的示例,包括一个构建器,添加边缘或使用资源颜色的可能性

    class SeparatorDecoration constructor(ctx: Context, @ColorRes dividerColor: Int, heightDp: Float) :
    RecyclerView.ItemDecoration() {

    private val mPaints = Paint()

    init {
        mPaints.color = dividerColor
        val thickness = TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP,
            heightDp,
            ctx.resources.displayMetrics
        )
        mPaints.strokeWidth = thickness
    }

    override fun getItemOffsets(
        outRect: Rect,
        view: View,
        parent: RecyclerView,
        state: RecyclerView.State
    ) {
        val params = view.layoutParams as RecyclerView.LayoutParams

        // and add a separator to any view but the last one
        val p = params.viewAdapterPosition

        // and add a separator to any view but the last one
        if (p < state.itemCount) outRect[0, 0, 0] =
            mPaints.strokeWidth.toInt() // left, top, right, bottom
        else outRect.setEmpty() // 0, 0, 0, 0
    }

    override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {

        // we set the stroke width before, so as to correctly draw the line we have to offset by width / 2
        val offset = (mPaints.strokeWidth / 2).roundToInt()

        // this will iterate over every visible view
        for (i in 0 until parent.childCount) {
            // get the view
            val view: View = parent.getChildAt(i)
            val params = view.layoutParams as RecyclerView.LayoutParams

            // get the position
            val position = params.viewAdapterPosition

            // and finally draw the separator
            if (position < state.itemCount) {
                c.drawLine(
                    view.left.toFloat(),
                    (view.bottom + offset).toFloat(),
                    view.right.toFloat(), (view.bottom + offset).toFloat(), mPaints
                )
            }
        }
    }
  }

设置很简单。只需将您的装饰与其余的初始设置一起添加到您的recyclerView。

 val decoration = SeparatorDecoration(context, R.color.primaryColor, 1.5f)
 recyclerview.addItemDecoration(decoration)

其他回答

只需添加

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

此外,您可能还需要添加依赖项 实现“com.android.support: recyclerview-v7:28.0.0”

为了自定义它,你可以添加一个自定义drawable:

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>

RecyclerView和ListView有点不同。实际上,RecyclerView需要一个类似ListView的结构。例如,线性布局。LinearLayout有用于划分每个元素的参数。

在下面的代码中,我有一个RecyclerView由一个线性布局中的CardView对象组成,其中有一个“填充”,将在项目之间放置一些空间。把空间缩小,就能得到一条线。

下面是recyclerview_layout.xml文件中的Recycler视图:

<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>

这里是每个项目看起来像(它显示为分割由于android:填充在线性布局包围一切)在另一个文件: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>

使用这个类在你的RecyclerView中设置分隔符。

public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {

    private int spanCount;
    private int spacing;
    private boolean includeEdge;

    public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
        this.spanCount = spanCount;
        this.spacing = spacing;
        this.includeEdge = includeEdge;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        int position = parent.getChildAdapterPosition(view); // Item position
        int column = position % spanCount; // Item column

        if (includeEdge) {
            outRect.left = spacing - column * spacing / spanCount; // spacing - column * ((1f / spanCount) * spacing)
            outRect.right = (column + 1) * spacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing)

            if (position < spanCount) { // Top edge
                outRect.top = spacing;
            }
            outRect.bottom = spacing; // Item bottom
        } else {
            outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing)
            outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f / spanCount) * spacing)
            if (position >= spanCount) {
                outRect.top = spacing; // Item top
            }
        }
    }
}

这个链接对我来说很有吸引力:

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));

为了在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 :)
        }
    }
})

对于我粘贴的代码,有几件事需要考虑:

You don't really need to call super.getItemOffsets but I chose to, because I want to extend the behavior defined by the base class. If the library got an update doing more logic behind the scenes, we would miss it. As an alternative to adding top spacing to the Rect, you could also add bottom spacing, but the logic related to getting the last item of the adapter is more complex, so this might be slightly better. I used an extension property to convert a simple integer to dps: 8.dp. Something like this might work:

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()