RecyclerView使用ItemDecoration繪製分割線

一、 摘要

本文介紹使用RecyclerView的抽象內部類ItemDecoration實現ItemView分割線的繪製。


二、 方法分析

實現分割線的繪製,需要重寫兩個方法:getItemOffsets()和onDraw()。

1. ItemDecoration.getItemOffsets

public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state)

看方法名,獲取item的偏移量,outRect是item的偏移量矩形區域,對其設置四個方向的值,便起到設置該item在四個方向上的偏移量的作用,這個偏移量的實際效果,是擴展item本身的區域,例如:

outRect.set(0, 0, 0, 1);

該代碼的效果是讓這個item的bottom位置空出1dp的高度。

獲取當前item對應位置的方法:

int position = parent.getChildAdapterPosition(view);

2. ItemDecoration.onDraw

public void onDraw(@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNull RecyclerView.State state)

這個方法就是具體的繪製操作了,該方法中,我們應該和上一個方法保持一致,在位置相對應時纔去繪製canvas,我們需要通過遍歷parent來獲取每個item對應的位置:

for (int i = 0; i < parent.getChildCount(); i++) {
    View view = parent.getChildAt(i);
    int position = parent.getChildAdapterPosition(view);
    // TODO draw canvas
}

3. RecyclerView.addItemDecoration

public void addItemDecoration(@NonNull ItemDecoration decor)

對RecyclerView添加一個Item裝飾器


4. RecyclerView.invalidateItemDecorations

public void invalidateItemDecorations()

刷新item裝飾器,該方法內部會調用裝飾器的getItemOffsets()和onDraw()方法。


三、 示例

假設現在我們的需求是:有一個垂直方向的RecyclerView,在指定位置item的底部加上一條1dp高的分割線:

先自定義一個ItemDecoration:

public class DemoItemDecoration extends RecyclerView.ItemDecoration {

    private final static int DIVIDE_HEIGHT = 1;
    private Context mContext;
    private Paint mPaint;
    private int mDividerPosition;

    public DemoItemDecoration(Context context) {
        mContext = context;
        mPaint = new Paint();
        mPaint.setColor(Color.BLACK);
    }

    public void setPosition(int position) {
        mDividerPosition = position;
    }

    @Override
    public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        int position = parent.getChildAdapterPosition(view);
        if (position == mDividerPosition) {
            outRect.set(0, 0, 0, dip2px(DIVIDE_HEIGHT));
        }
    }

    @Override
    public void onDraw(@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
        super.onDraw(canvas, parent, state);
        for (int i = 0; i < parent.getChildCount(); i++) {
            View view = parent.getChildAt(i);
            int position = parent.getChildAdapterPosition(view);
            if (position == mDividerPosition) {
                drawDivider(canvas, view);
                return;
            }
        }
    }

    /**
     * 在{@link #getItemOffsets}中,我們已經讓item底部空出了1dp的位置,現在我們要在這1dp高的區域內填充,實現分割線
     *
     * @param canvas
     * @param view
     */
    private void drawDivider(Canvas canvas, View view) {
        int left = view.getLeft();
        int right = view.getRight();
        int top = view.getBottom();
        int bottom = top + dip2px(DIVIDE_HEIGHT);
        canvas.drawRect(left, top, right, bottom, mPaint);
    }

    private int dip2px(int dip) {
        float density = mContext.getResources().getDisplayMetrics().density;
        return (int) (dip * density + 0.5f);
    }
}

然後將這個裝飾器應用於RecyclerView上:

private RecyclerView mRecyclerView;
private DemoItemDecoration mItemDecoration;

private void initView(){
    mRecyclerView = findViewById(R.id.rvDemo);
    mItemDecoration = new DemoItemDecoration(this);
    mRecyclerView.addItemDecoration(mItemDecoration);
}

private void updateView(int position){
    mItemDecoration.setPosition(position);
    mRecyclerView.invalidateItemDecorations();
}

四、 總結

在學會使用Item裝飾器之前,我們想實現在RecyclerView中插入分割線,可能得定義一個ViewHolder,然後在Adapter中進行適配,如今我們可以利用裝飾器更加優雅地實現這個功能。同理,我們可以在Item的頂部加上組名進行分組,比如實現一個聯繫人列表,組名是大寫首字母。

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