一款實用的RecyclerView的線性佈局分割線

       RecyclerView的功能十分強大,但要爲其添加分割線卻不如ListView那麼簡單。但是RecyclerView的分割線遠比ListView的靈活,那怎樣優雅地爲RecyclerView添加分割線呢?封裝一個繼承自ItemDecoration的類即可。以下爲我參照多方資料封裝的分割線類,希望能爲廣大同胞們出一份力,讓各位單身狗們能夠有更多的時間去撩妹。

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.support.annotation.IntDef;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.view.View;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

public class LinearDivider extends RecyclerView.ItemDecoration {

    public static final int HORIZONTAL = LinearLayoutManager.HORIZONTAL;
    public static final int VERTICAL = LinearLayoutManager.VERTICAL;

    private static final int[] ATTRS = new int[]{
            android.R.attr.listDivider
    };

    private final SparseIntArray mDividerOffsets = new SparseIntArray();
    private final SparseArray<DrawableCreator> mTypeDrawableFactories = new SparseArray<>();

    @IntDef({
            HORIZONTAL,
            VERTICAL
    })
    @Retention(RetentionPolicy.SOURCE)
    private @interface Orientation {
    }

    @Orientation
    private int mOrientation;
    private Drawable mDivider;
    private boolean isIncludeEdge;
    private int mSize;

    public LinearDivider(Context context) {
        this.isIncludeEdge = false;
        resolveDivider(context);
        setOrientation(VERTICAL);
    }

    private void resolveDivider(Context context) {
        final TypedArray a = context.obtainStyledAttributes(ATTRS);
        mDivider = a.getDrawable(0);
        a.recycle();
    }

    public LinearDivider(int mColor, int mSize) {
        this.mDivider = new ColorDrawable(mColor);
        this.mSize = mSize;
        this.isIncludeEdge = false;
        setOrientation(VERTICAL);
    }

    public LinearDivider(int mColor, int mSize, @Orientation int orientation) {
        this.isIncludeEdge = false;
        this.mDivider = new ColorDrawable(mColor);
        this.mSize = mSize;
        setOrientation(orientation);
    }

    public LinearDivider(int mColor, int mSize, boolean isIncludeEdge) {
        this.isIncludeEdge = isIncludeEdge;
        this.mDivider = new ColorDrawable(mColor);
        this.mSize = mSize;
        setOrientation(VERTICAL);
    }

    public LinearDivider(int mColor, int mSize, @Orientation int orientation, boolean isIncludeEdge) {
        this.isIncludeEdge = isIncludeEdge;
        this.mDivider = new ColorDrawable(mColor);
        this.mSize = mSize;
        setOrientation(orientation);
    }

    public void setOrientation(@Orientation int orientation) {
        mOrientation = orientation;
    }

    public void setDivider(Drawable divider) {
        this.mDivider = divider;
    }

    public void setColor(int mColor) {
        this.mDivider = new ColorDrawable(mColor);
    }

    public void setSize(int mSize) {
        this.mSize = mSize;
    }

    public void setIncludeEdge(boolean isIncludeEdge) {
        this.isIncludeEdge = isIncludeEdge;
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        if (mOrientation == VERTICAL) {
            drawVerticalDividers(c, parent);
        } else {
            drawHorizontalDividers(c, parent);
        }
    }

    private void drawVerticalDividers(Canvas c, RecyclerView parent) {
        final int left = parent.getPaddingLeft();
        final int right = parent.getWidth() - parent.getPaddingRight();

        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
            final Drawable divider = getDivider(parent, params.getViewAdapterPosition());
            final int top = child.getBottom() + params.bottomMargin + Math.round(ViewCompat.getTranslationY(child));
            final int bottom = top + mSize;

            mDividerOffsets.put(params.getViewAdapterPosition(), mSize);

            if (isIncludeEdge && i == 0) {
                final int edgeTop = child.getTop() - params.topMargin - mSize;
                final int edgeBottom = child.getTop() - params.topMargin;
                divider.setBounds(left, edgeTop, right, edgeBottom);
                divider.draw(c);
            }

            if (isIncludeEdge || i != childCount - 1) {
                divider.setBounds(left, top, right, bottom);
                divider.draw(c);
            }
        }
    }

    private void drawHorizontalDividers(Canvas c, RecyclerView parent) {
        final int top = parent.getPaddingTop();
        final int bottom = parent.getHeight() - parent.getPaddingBottom();

        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
            final Drawable divider = getDivider(parent, params.getViewAdapterPosition());
            final int left = child.getRight() + params.rightMargin + Math.round(ViewCompat.getTranslationX(child));
            final int right = left + mSize;

            mDividerOffsets.put(params.getViewAdapterPosition(), mSize);

            if (isIncludeEdge && i == 0) {
                final int edgeLeft = child.getLeft() - params.leftMargin - mSize;
                final int edgeRight = child.getLeft() - params.leftMargin;
                divider.setBounds(edgeLeft, top, edgeRight, bottom);
                divider.draw(c);
            }

            if (isIncludeEdge || i != childCount - 1) {
                divider.setBounds(left, top, right, bottom);
                divider.draw(c);
            }
        }
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        final int adapterPosition = parent.getChildAdapterPosition(view);
        int edge = 0;
        if (isIncludeEdge) {
            if (adapterPosition == 0) {
                edge = mSize;
            }
        } else {
            if (adapterPosition == parent.getAdapter().getItemCount() - 1) {
                return;
            }
        }

        if (mDividerOffsets.indexOfKey(adapterPosition) < 0) {
            mDividerOffsets.put(adapterPosition, mSize);
        }

        if (mOrientation == VERTICAL) {
            outRect.set(0, edge, 0, mDividerOffsets.get(parent.getChildAdapterPosition(view)));
        } else {
            outRect.set(edge, 0, mDividerOffsets.get(parent.getChildAdapterPosition(view)), 0);
        }
    }

    private Drawable getDivider(RecyclerView parent, int adapterPosition) {
        final RecyclerView.Adapter adapter = parent.getAdapter();
        final int itemType = adapter.getItemViewType(adapterPosition);
        final DrawableCreator drawableCreator = mTypeDrawableFactories.get(itemType);

        if (drawableCreator != null) {
            return drawableCreator.create(parent, adapterPosition);
        }

        return mDivider;
    }

    interface DrawableCreator {
        Drawable create(RecyclerView parent, int adapterPosition);
    }
}
      注意,這個分割線只供使用LinearLayoutManager的RecyclerView使用,方向可以是水平的,也可以是豎直的。裏面定義了好幾種構造方法,可以直接傳一個int型的color和int型的size,就可以創建一個指定顏色和指定寬度的分割線了,也可以通過setDivider傳入一個drawable的參數來創建自定義樣式的分割線,還可以再傳入方向orientation和邊界是否有分割線isIncludeEdge的參數直接對分割線進行定製,最後再調recyclerView.addItemDecoration(創建的分割線)就可以了。

      覺得好用還請點個贊喲。

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