為RecyclerView新增精美的分割線
前言
最近由於需求問題,需要寫一個列表。以前總是使用ListView,從來沒有用過RecyclerView。所以這次打算嘗試一下。然後就開始動手幹活了。RecyclerView佈局寫好了。然後寫adapter,一切正常。
發現沒有分割線有點難看。準備去佈局檔案裡面寫分割線,發現居然沒有divider這個屬性。後來百度了一下,原來RecyclerView設定分割線是程式碼中新增的。
recyclerView.addItemDecoration(new DividerItemDecoration(context,DividerItemDecoration.VERTICAL));
現在Google已經內建了DividerItemDecoration類,以前是沒有這個類的,需要我們自己寫,現在越來越方便了。第一個引數需要傳入Context,第二個引數是分割線的型別,我這個是表示vertical。當然,如果你有需要你完全可以設定為horizontal。你以為這樣就設定好分割線了嗎?答案顯而易見,沒有。
接下來,你需要在res目錄下drawable的資料夾裡面新建一個divider.xml檔案。名字你可以按你自己的喜好來設定。
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/gray"/>
<size android:height="0.1dp"/>
</shape >
我這裡gray是#D0D0D0,大家也可以自己修改。
再然後,你需要在values資料夾裡面的styles檔案裡面新增這樣一行程式碼。
<item name="android:listDivider">@drawable/divider</item>
好,寫到這裡。大功告成。先執行一下看看效果。
嗯?突然發現最後一行資料的下面也有分割線,這樣不太美觀。接下來我們繼續修改。
聰明的小夥伴可能已經知道怎麼修改了。答案就是前面提到的DividerItemDecoration這個類。我們進去看看。
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
public static final int VERTICAL = LinearLayout.VERTICAL;
private static final int[] ATTRS = new int[]{ android.R.attr.listDivider };
private Drawable mDivider;
/**
* Current orientation. Either {@link #HORIZONTAL} or {@link #VERTICAL}.
*/
private int mOrientation;
private final Rect mBounds = new Rect();
/**
* Creates a divider {@link RecyclerView.ItemDecoration} that can be used with a
* {@link LinearLayoutManager}.
*
* @param context Current context, it will be used to access resources.
* @param orientation Divider orientation. Should be {@link #HORIZONTAL} or {@link #VERTICAL}.
*/
public DividerItemDecoration(Context context, int orientation) {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
setOrientation(orientation);
}
/**
* Sets the orientation for this divider. This should be called if
* {@link RecyclerView.LayoutManager} changes orientation.
*
* @param orientation {@link #HORIZONTAL} or {@link #VERTICAL}
*/
public void setOrientation(int orientation) {
if (orientation != HORIZONTAL && orientation != VERTICAL) {
throw new IllegalArgumentException(
"Invalid orientation. It should be either HORIZONTAL or VERTICAL");
}
mOrientation = orientation;
}
/**
* 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;
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
if (parent.getLayoutManager() == null) {
return;
}
if (mOrientation == VERTICAL) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}
@SuppressLint("NewApi")
private void drawVertical(Canvas canvas, RecyclerView parent) {
canvas.save();
final int left;
final int right;
if (parent.getClipToPadding()) {
left = parent.getPaddingLeft();
right = parent.getWidth() - parent.getPaddingRight();
canvas.clipRect(left, parent.getPaddingTop(), right,
parent.getHeight() - parent.getPaddingBottom());
} else {
left = 0;
right = parent.getWidth();
}
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
parent.getDecoratedBoundsWithMargins(child, mBounds);
final int bottom = mBounds.bottom + Math.round(ViewCompat.getTranslationY(child));
final int top = bottom - mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(canvas);
}
canvas.restore();
}
@SuppressLint("NewApi")
private void drawHorizontal(Canvas canvas, RecyclerView parent) {
canvas.save();
final int top;
final int bottom;
if (parent.getClipToPadding()) {
top = parent.getPaddingTop();
bottom = parent.getHeight() - parent.getPaddingBottom();
canvas.clipRect(parent.getPaddingLeft(), top,
parent.getWidth() - parent.getPaddingRight(), bottom);
} else {
top = 0;
bottom = parent.getHeight();
}
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
parent.getLayoutManager().getDecoratedBoundsWithMargins(child, mBounds);
final int right = mBounds.right + Math.round(ViewCompat.getTranslationX(child));
final int left = right - mDivider.getIntrinsicWidth();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(canvas);
}
canvas.restore();
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) {
if (mOrientation == VERTICAL) {
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else {
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
}
}
}
裡面有這樣一個方法drawVertical,沒錯它就是在這個方法裡面迴圈的繪製每一條分割線的。所以我們只需要將for迴圈裡面的i<childCount
改為i<childCount-1
就可以了。這裡我用到的是垂直方向上的,所以drawHorizontal方法裡面的資料我就沒有修改。大家自己按需求修改哈。但是DividerItemDecoration這個類我們可能不能直接修改,我們可以新建一個類DividerItemsDecoration繼承自RecyclerView.ItemDecoration,將DividerItemDecoration裡面的程式碼copy過來,將我上面說的東西修改掉,這樣就真的大功告成了。接下來執行我們的程式,就可以看到精美的
分割線了。是不是很開心。