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

文章更新中

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章