文章歡迎轉載,轉載請註明出處:文章首發於【Karen Chia の 程序人生】RecyclerView系列 - 如何優雅的實現分割線
效果圖不是我想要的效果,怎麼辦?
查看關於 RecyclerView 系列的其它文章,總有你想要的效果 ↓↓↓
KarenChia 的 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()
文章更新中