这是之前在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"/>

在这种情况下,是否可以定义边距和/或直接添加自定义分隔符视图到列表项的布局中,或者是否有更好的方法来实现我的目标?


当前回答

如果有人想为spaceBetween, paddingLeft, paddingTop, paddingRight和paddingBottom设置不同的值。

class ItemPaddingDecoration(
    private val spaceBetween: Int,
    private val paddingLeft: Int = spaceBetween,
    private val paddingTop: Int = spaceBetween,
    private val paddingRight: Int = spaceBetween,
    private val paddingBottom: Int = spaceBetween
) : RecyclerView.ItemDecoration() {

    override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
        val position = parent.getChildAdapterPosition(view)
        val orientation = when (val layoutManager = parent.layoutManager) {
            is LinearLayoutManager -> {
                layoutManager.orientation
            }
            is GridLayoutManager -> {
                layoutManager.orientation
            }
            else -> {
                RecyclerView.HORIZONTAL
            }
        }
        if (orientation == RecyclerView.HORIZONTAL) {
            when {
                position == 0 -> {
                    outRect.set(paddingLeft, paddingTop, spaceBetween, paddingBottom)
                }
                position < parent.adapter!!.itemCount - 1 -> {
                    outRect.set(0, paddingTop, spaceBetween, paddingBottom)
                }
                else -> {
                    outRect.set(0, paddingTop, paddingRight, paddingBottom)
                }
            }
        } else {
            when {
                position == 0 -> {
                    outRect.set(paddingLeft, paddingTop, paddingRight, paddingBottom)
                }
                position < parent.adapter!!.itemCount - 1 -> {
                    outRect.set(paddingLeft, 0, paddingRight, spaceBetween)
                }
                else -> {
                    outRect.set(paddingLeft, 0, paddingRight, paddingBottom)
                }
            }
        }
    }
}

其他回答

RecyclerView没有为绘制列表分隔符提供一个简单的接口。但实际上它为我们提供了更灵活的 划分隔线的方法。

我们使用RecyclerView。用分隔线或任何你想要的东西来装饰RecyclerView的瓷砖。这也是为什么它被称为ItemDecoration。

如《材料设计指南》所述:

分隔符位于贴图的基线内。

所以如果你想遵循材料设计指南,你不需要额外的空间来画分隔线。把它们画在瓷砖上。然而,你有权利做任何你想做的事。所以我实现了一个让你能够设置嵌入以及在瓷砖上/下面绘制的功能。

public class InsetDivider extends RecyclerView.ItemDecoration {

    public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
    public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;

    private Paint mPaint;
    // in pixel
    private int mDividerHeight;
    // left inset for vertical list, top inset for horizontal list
    private int mFirstInset;
    // right inset for vertical list, bottom inset for horizontal list
    private int mSecondInset;
    private int mColor;
    private int mOrientation;
    // set it to true to draw divider on the tile, or false to draw beside the tile.
    // if you set it to false and have inset at the same time, you may see the background of
    // the parent of RecyclerView.
    private boolean mOverlay;

    private InsetDivider() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Paint.Style.FILL);
    }

    public int getDividerHeight() {
        return mDividerHeight;
    }

    public void setDividerHeight(int dividerHeight) {
        this.mDividerHeight = dividerHeight;
    }

    public int getFirstInset() {
        return mFirstInset;
    }

    public void setFirstInset(int firstInset) {
        this.mFirstInset = firstInset;
    }

    public int getSecondInset() {
        return mSecondInset;
    }

    public void setSecondInset(int secondInset) {
        this.mSecondInset = secondInset;
    }

    public int getColor() {
        return mColor;
    }

    public void setColor(int color) {
        this.mColor = color;
        mPaint.setColor(color);
    }

    public int getOrientation() {
        return mOrientation;
    }

    public void setOrientation(int orientation) {
        this.mOrientation = orientation;
    }

    public boolean getOverlay() {
        return mOverlay;
    }

    public void setOverlay(boolean overlay) {
        this.mOverlay = overlay;
    }

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        if (mOrientation == VERTICAL_LIST) {
            drawVertical(c, parent);
        } else {
            drawHorizontal(c, parent);
        }
    }

    protected void drawVertical(Canvas c, RecyclerView parent) {
        final int left = parent.getPaddingLeft() + mFirstInset;
        final int right = parent.getWidth() - parent.getPaddingRight() - mSecondInset;
        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            if (parent.getChildAdapterPosition(child) == (parent.getAdapter().getItemCount() - 1)) {
                continue;
            }
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
            final int bottom;
            final int top;
            if (mOverlay) {
                bottom = child.getBottom() + params.bottomMargin + Math.round(ViewCompat.getTranslationY(child));
                top = bottom - mDividerHeight;
            } else {
                top = child.getBottom() + params.bottomMargin + Math.round(ViewCompat.getTranslationY(child));
                bottom = top + mDividerHeight;
            }
            c.drawRect(left, top, right, bottom, mPaint);
        }
    }

    protected void drawHorizontal(Canvas c, RecyclerView parent) {
        final int top = parent.getPaddingTop() + mFirstInset;
        final int bottom = parent.getHeight() - parent.getPaddingBottom() - mSecondInset;
        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            if (parent.getChildAdapterPosition(child) == (parent.getAdapter().getItemCount() - 1)) {
                continue;
            }
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                .getLayoutParams();
            final int right;
            final int left;
            if (mOverlay) {
                right = child.getRight() + params.rightMargin + Math.round(ViewCompat.getTranslationX(child));
                left = right - mDividerHeight;
            } else {
                left = child.getRight() + params.rightMargin + Math.round(ViewCompat.getTranslationX(child));
                right = left + mDividerHeight;
            }
            c.drawRect(left, top, right, bottom, mPaint);
        }
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        if (mOverlay) {
            super.getItemOffsets(outRect, view, parent, state);
            return;
        }

        if (mOrientation == VERTICAL_LIST) {
            outRect.set(0, 0, 0, mDividerHeight);
        } else {
            outRect.set(0, 0, mDividerHeight, 0);
        }
    }

    /**
     * Handy builder for creating {@link InsetDivider} instance.
     */
    public static class Builder {

        private Context mContext;
        private int mDividerHeight;
        private int mFirstInset;
        private int mSecondInset;
        private int mColor;
        private int mOrientation;
        private boolean mOverlay = true; // set default to true to follow Material Design Guidelines

        public Builder(Context context) {
            mContext = context;
        }

        public Builder dividerHeight(int dividerHeight) {
            mDividerHeight = dividerHeight;
            return this;
        }

        public Builder insets(int firstInset, int secondInset) {
            mFirstInset = firstInset;
            mSecondInset = secondInset;
            return this;
        }

        public Builder color(@ColorInt int color) {
            mColor = color;
            return this;
        }

        public Builder orientation(int orientation) {
            mOrientation = orientation;
            return this;
        }

        public Builder overlay(boolean overlay) {
            mOverlay = overlay;
            return this;
        }

        public InsetDivider build() {
            InsetDivider insetDivider = new InsetDivider();

            if (mDividerHeight == 0) {
                // Set default divider height to 1dp.
                 insetDivider.setDividerHeight(mContext.getResources().getDimensionPixelSize(R.dimen.divider_height));
            } else if (mDividerHeight > 0) {
                insetDivider.setDividerHeight(mDividerHeight);
            } else {
                throw new IllegalArgumentException("Divider's height can't be negative.");
            }

            insetDivider.setFirstInset(mFirstInset < 0 ? 0 : mFirstInset);
            insetDivider.setSecondInset(mSecondInset < 0 ? 0 : mSecondInset);

            if (mColor == 0) {
                throw new IllegalArgumentException("Don't forget to set color");
            } else {
                insetDivider.setColor(mColor);
            }

            if (mOrientation != InsetDivider.HORIZONTAL_LIST && mOrientation != InsetDivider.VERTICAL_LIST) {
                throw new IllegalArgumentException("Invalid orientation");
            } else {
                insetDivider.setOrientation(mOrientation);
            }

            insetDivider.setOverlay(mOverlay);

            return insetDivider;
        }
    }
}

你可以这样使用它:

ItemDecoration divider = new InsetDivider.Builder(this)
                            .orientation(InsetDivider.VERTICAL_LIST)
                            .dividerHeight(getResources().getDimensionPixelSize(R.dimen.divider_height))
                            .color(getResources().getColor(R.color.colorAccent))
                            .insets(getResources().getDimensionPixelSize(R.dimen.divider_inset), 0)
                            .overlay(true)
                            .build();

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.addItemDecoration(divider);

我还写了一个关于如何实现ItemDecoration以及如何使用它们的演示应用程序。你可以查看我的GitHub存储库Dividers-For-RecyclerView。它有三个实现:

下隔板 叠加分隔器 插入分隔器

由于没有正确的方法来实现这一点,但正确使用材质设计,我只是做了以下技巧,直接在列表项上添加一个分隔符:

<View
    android:layout_width="match_parent"
    android:layout_height="1dp"
    android:background="@color/dividerColor"/>

我有一个非常简单的方法在RecyclerView中添加一个分隔符。使用自定义适配器修改回收器视图布局,然后与回收器视图项目一起添加带有背景色(将是分隔色)的线性布局,并添加1dp的高度(或根据您的要求)和宽度以匹配父级。

下面是一个示例代码。

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

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:padding="18dp">

        <TextView
            android:id="@+id/list_row_SNO"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight=".8"
            android:layout_gravity="end"
            android:text="44."
            android:textAlignment="center"
            android:textSize="24sp"
            android:textColor="@color/colorBlack"
            android:fontFamily="sans-serif-condensed" />

        <TextView
            android:id="@+id/list_row_Heading"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight=".2"
            android:layout_gravity="start"
            android:text="Student's application for leave and this what"
            android:textAlignment="textStart"
            android:textSize="24sp"
            android:textColor="@color/colorBlack"
            android:fontFamily="sans-serif-condensed" />

    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/colorHighlight">
    </LinearLayout>

</LinearLayout>

而不是创建一个形状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)

这实际上并不能解决问题,但是作为一种临时的解决方法,您可以在XML布局中的卡片上设置useCompatPadding属性,使其与在前lollipop版本中测量的相同。

card_view:cardUseCompatPadding="true"