1. 程式人生 > >為RecyclerView新增精美的分割線

為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過來,將我上面說的東西修改掉,這樣就真的大功告成了。接下來執行我們的程式,就可以看到精美的
分割線了。是不是很開心。

新增好的分割線