RecyclerView系列 - 如何优雅的实现分割线

文章欢迎转载,转载请注明出处:文章首发于【Karen Chia の 程序人生】RecyclerView系列 - 如何优雅的实现分割线

在这里插入图片描述
效果图不是我想要的效果,怎么办?

查看关于 RecyclerView 系列的其它文章,总有你想要的效果 ↓↓↓

KarenChia 的 RecyclerView 系列文章

RecyclerView系列 - RecyclerView的基本使用

RecyclerView系列 - 如何优雅的实现分割线

前言

在 RecyclerView 系列文章中,上一篇我们说到了 RecyclerView 的基本使用,期间提到了 RecyclerView 自身是不能设置分割线的,需要自行设置。本篇文章将从不同的“视角”讲解 RecyclerView 分割线的设置方法,文章建立在上一篇文章【RecyclerView系列 - RecyclerView的基本使用】的基础上,如果需要了解 RecyclerView 的基本使用、布局管理器的设置、数据适配器的设置等,请自行查看【RecyclerView系列 - RecyclerView的基本使用

1 RecyclerView 分割线设置方式一

更改列表子项 item 布局

这种方式设置的其实不是 RecyclerView 组件的分割线,只是更改了 item 的布局文件,在视觉效果上达到了分割线的效果。

item 的布局文件如下:

<?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="@android:color/white"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tvData"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:textColor="@android:color/black" />

    <View
        android:id="@+id/viewDivider"
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@android:color/holo_red_dark" />
</LinearLayout>

这里在原有文件的基础上,新增了 View 组件,用于实现视觉效果上的分割线。

可设置水平分割线的高度及颜色,更改 View 组件的相关属性即可。

这样的设置方法,在列表的最后一项是带有分割线的,需要在 adapter 的数据与视图进行绑定的方法中,控制 View 组件的显示与隐藏:

    /**
     * 将数据与 item 视图进行绑定
     */
    @Override
    public void onBindViewHolder(@NonNull RecyclerViewTestViewHolder holder, int position) {
        //最后一项 item 不显示分割线
        if (position == testDataList.size() - 1) {
            holder.viewDivider.setVisibility(View.GONE);
        } else {
            holder.viewDivider.setVisibility(View.VISIBLE);
        }
        holder.tvData.setText(testDataList.get(position));
    }

2 RecyclerView 分割线设置方式二

使用 Android 自带的分割线

RecyclerView 提供了 addItemDecoration(@NonNull ItemDecoration decor) 方法,可用于设置系统默认分割线

    public void addItemDecoration(@NonNull ItemDecoration decor) {
        addItemDecoration(decor, -1);
    }

给 RecyclerView 添加分割线

rvTest.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));

这里的 DividerItemDecoration 采用的是 RecyclerView 组件的背景色

<?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="match_parent"
    android:background="@color/app_bg"
    android:orientation="vertical">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rvTest"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/holo_red_dark" />
</LinearLayout>

在这里插入图片描述
采用这种方式设置的分割线的高度是系统默认的,我们无法修改分割线的高度。

为了方便修改分割线的高度、颜色,DividerItemDecoration 类提供了 setDrawable() 方法,供开发者自定义分割线。
    /**
     * Sets the {@link Drawable} for this divider.
     *
     * @param drawable Drawable that should be used as a divider.
     */
    public void setDrawable(@NonNull Drawable drawable) {
        if (drawable == null) {
            throw new IllegalArgumentException("Drawable cannot be null.");
        }
        mDivider = drawable;
    }

新建 Drawable 资源文件:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="@android:color/holo_blue_bright" />
    <size android:height="4dp" />
</shape>

为 RecyclerView 设置自定义的分割线样式:

DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL);
dividerItemDecoration.setDrawable(getResources().getDrawable(R.drawable.shape_recycler_view_divider));
rvTest.addItemDecoration(dividerItemDecoration);

在这里插入图片描述
稍微复杂一点的,可以为分割线定义渐变色,修改 Drawable 资源文件:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <gradient
        android:centerColor="@android:color/holo_blue_bright"
        android:endColor="@android:color/background_dark"
        android:startColor="@android:color/holo_red_dark" />
    <size android:height="4dp" />
</shape>

在这里插入图片描述

3 RecyclerView 分割线设置方式三

利用 item 与 RecyclerView 之间的 Margin,达到显示分割线的效果,分割线的颜色为 RecyclerView 的背景色。

在 RecyclerView 适配器中的 onCreateViewHolder()方法中,加载 item 布局时进行设置:

    /**
     * 加载 item 的布局文件
     */
    @NonNull
    @Override
    public RecyclerViewTestViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(mContext).inflate(R.layout.item_recycler_view_test, parent, false);
        RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams();
        layoutParams.bottomMargin = 10;
        view.setLayoutParams(layoutParams);
        return new RecyclerViewTestViewHolder(view);
    }

在这里插入图片描述

4 RecyclerView 分割线设置方式四

在之前提到的使用 Android 默认的方式来设置分割线的方法中,可以看到 DividerItemDecoration 类继承了 RecyclerView.ItemDecoration,那么我们也可以继承 RecyclerView.ItemDecoration,从而实现自己的分割线。

先看下源码:

    /**
     * An ItemDecoration allows the application to add a special drawing and layout offset
     * to specific item views from the adapter's data set. This can be useful for drawing dividers
     * between items, highlights, visual grouping boundaries and more.
     *
     * <p>All ItemDecorations are drawn in the order they were added, before the item
     * views (in {@link ItemDecoration#onDraw(Canvas, RecyclerView, RecyclerView.State) onDraw()}
     * and after the items (in {@link ItemDecoration#onDrawOver(Canvas, RecyclerView,
     * RecyclerView.State)}.</p>
     */
    public abstract static class ItemDecoration {
        /**
         * Draw any appropriate decorations into the Canvas supplied to the RecyclerView.
         * Any content drawn by this method will be drawn before the item views are drawn,
         * and will thus appear underneath the views.
         *
         * @param c Canvas to draw into
         * @param parent RecyclerView this ItemDecoration is drawing into
         * @param state The current state of RecyclerView
         */
        public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull State state) {
            onDraw(c, parent);
        }

        /**
         * @deprecated
         * Override {@link #onDraw(Canvas, RecyclerView, RecyclerView.State)}
         */
        @Deprecated
        public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent) {
        }

        /**
         * Draw any appropriate decorations into the Canvas supplied to the RecyclerView.
         * Any content drawn by this method will be drawn after the item views are drawn
         * and will thus appear over the views.
         *
         * @param c Canvas to draw into
         * @param parent RecyclerView this ItemDecoration is drawing into
         * @param state The current state of RecyclerView.
         */
        public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent,
                @NonNull State state) {
            onDrawOver(c, parent);
        }

        /**
         * @deprecated
         * Override {@link #onDrawOver(Canvas, RecyclerView, RecyclerView.State)}
         */
        @Deprecated
        public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent) {
        }


        /**
         * @deprecated
         * Use {@link #getItemOffsets(Rect, View, RecyclerView, State)}
         */
        @Deprecated
        public void getItemOffsets(@NonNull Rect outRect, int itemPosition,
                @NonNull RecyclerView parent) {
            outRect.set(0, 0, 0, 0);
        }

        /**
         * Retrieve any offsets for the given item. Each field of <code>outRect</code> specifies
         * the number of pixels that the item view should be inset by, similar to padding or margin.
         * The default implementation sets the bounds of outRect to 0 and returns.
         *
         * <p>
         * If this ItemDecoration does not affect the positioning of item views, it should set
         * all four fields of <code>outRect</code> (left, top, right, bottom) to zero
         * before returning.
         *
         * <p>
         * If you need to access Adapter for additional data, you can call
         * {@link RecyclerView#getChildAdapterPosition(View)} to get the adapter position of the
         * View.
         *
         * @param outRect Rect to receive the output.
         * @param view    The child view to decorate
         * @param parent  RecyclerView this ItemDecoration is decorating
         * @param state   The current state of RecyclerView.
         */
        public void getItemOffsets(@NonNull Rect outRect, @NonNull View view,
                @NonNull RecyclerView parent, @NonNull State state) {
            getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(),
                    parent);
        }
    }

ItemDecoration 类包含了三个主要的方法:onDraw()、onDrawOver()、getItemOffsets()

文章更新中

发布了101 篇原创文章 · 获赞 52 · 访问量 20万+

猜你喜欢

转载自blog.csdn.net/ZhaiKun68/article/details/100591943