RecyclerView通用分割線

使用方式

       listContent.addItemDecoration(
                Divider.builder().
                        color(getResources().getColor(R.color.bgDefaultColor))
                        .height(3)
                        .build()
        );

使用范圍

GridLayoutManager;
LinearLayoutManager;
StaggeredGridLayoutManager;

代碼來(lái)源

來(lái)自網(wǎng)絡(luò),已忘記開源作者

源碼粘貼


/**
 * 描述: RecyclerView通用分割線
 * @author Smile
 */
@SuppressWarnings("unused")
public class Divider extends RecyclerView.ItemDecoration {

    private Drawable dividerDrawable;
    private final int DEFAULT_LINE_WIDTH = 10;
    private final int DEFAULT_LINE_HEIGHT = 20;

    private int lineWidth = DEFAULT_LINE_WIDTH;// 線的寬度
    private int lineHeight = DEFAULT_LINE_HEIGHT;// 線的高度
    private int headerCount = 0;// 頭的數(shù)量
    private int footerCount = 0;// 尾的數(shù)量

    Divider() {
        dividerDrawable = new ColorDrawable(Color.GRAY);
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        if (isSkipDraw(parent, view))
            return;// 跳過(guò)账嚎,不繪制
        int currentPosition = parent.getChildAdapterPosition(view);
        int spanCount = getSpanCount(parent);// 水平個(gè)數(shù),線性布局為-1
        int childCount = parent.getAdapter().getItemCount();// 總個(gè)數(shù)
        int right = lineWidth;
        int bottom = lineHeight;
        if (isNotDrawBottom(view, parent, currentPosition, spanCount, childCount))
            // 如果是最后一行机错,則不需要繪制底部
            bottom = 0;
        if (isNotDrawRight(view, parent, currentPosition, spanCount, childCount))
            // 如果是最后一列,則不需要繪制右邊
            right = 0;
        outRect.set(0, 0, right, bottom);
    }


    @Override
    public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
        drawHorizontal(canvas, parent, lineWidth, lineHeight);
        drawVertical(canvas, parent, lineWidth, lineHeight);
    }

    /**
     * 是否不繪制右部
     *
     * @param view            當(dāng)前的view,StaggeredGridLayoutManager 用
     * @param parent          RecyclerView
     * @param currentPosition 當(dāng)前的位置乡摹,GridLayoutManager、LinearLayoutManager用
     * @param spanCount       列數(shù)
     * @param adapterCount    adapter的總數(shù)
     * @return 返回true代表不繪制右部采转,返回false聪廉,代表繪制右部
     */
    private boolean isNotDrawRight(View view, RecyclerView parent, int currentPosition, int spanCount, int adapterCount) {
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {
            // GridLayoutManager
            currentPosition -= getHeaderCount();// 去掉頭的數(shù)量
            adapterCount -= getHeaderCount() + getFooterCount();// 去掉頭、尾的數(shù)量
            // 判斷最后一個(gè)是否繪制
            if (((GridLayoutManager) layoutManager).getOrientation() == LinearLayoutManager.VERTICAL) {
                // 垂直故慈,判斷是否是最后一列
                return (currentPosition + 1) % spanCount == 0;
            } else {
                // 水平板熊,判斷是不是最后的
                if (adapterCount % spanCount == 0)
                    return currentPosition >= adapterCount - spanCount;
                else
                    return currentPosition >= adapterCount - adapterCount % spanCount;
            }
        } else if (layoutManager instanceof LinearLayoutManager) {
            // LinearLayoutManager
            // 判斷最后一個(gè)是否繪制,垂直察绷,不繪制右邊干签,直接返回true,水平,判斷拆撼,是否是最后一個(gè)
            return ((LinearLayoutManager) layoutManager).getOrientation() == LinearLayout.VERTICAL || currentPosition == adapterCount - getFooterCount() - 1;
        } else if (layoutManager instanceof StaggeredGridLayoutManager) {
            // 判斷最后一個(gè)是否繪制容劳,垂直,判斷是否是最后一列闸度,是返回true竭贩,水平句惯,都顯示雨膨,返回false
            StaggeredGridLayoutManager.LayoutParams lp = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
            return ((StaggeredGridLayoutManager) layoutManager).getOrientation() == StaggeredGridLayoutManager.VERTICAL && (lp.getSpanIndex() + 1) % spanCount == 0;
        }
        return false;
    }

    /**
     * 是否不繪制底部
     *
     * @param view            當(dāng)前的view,StaggeredGridLayoutManager 用
     * @param parent          RecyclerView
     * @param currentPosition 當(dāng)前的位置赡勘,GridLayoutManager哟冬、LinearLayoutManager用
     * @param spanCount       列數(shù)
     * @param adapterCount    adapter的總數(shù)
     * @return 返回true代表不繪制底部楼熄,返回false,代表繪制底部
     */
    private boolean isNotDrawBottom(View view, RecyclerView parent, int currentPosition, int spanCount, int adapterCount) {
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {
            // GridLayoutManager
            currentPosition -= getHeaderCount();// 去掉頭的數(shù)量
            adapterCount -= getHeaderCount() + getFooterCount();// 去掉頭柒傻、尾的數(shù)量
            // 判斷最后一個(gè)是否繪制
            if (((GridLayoutManager) layoutManager).getOrientation() == LinearLayoutManager.VERTICAL) {
                // 垂直孝赫,判斷是不是最后的
                if (adapterCount % spanCount == 0)
                    return currentPosition >= adapterCount - spanCount;
                else
                    return currentPosition >= adapterCount - adapterCount % spanCount;
            } else {
                // 水平,判斷是不是最后一列
                return (currentPosition + 1) % spanCount == 0;
            }
        } else if (layoutManager instanceof LinearLayoutManager) {
            // LinearLayoutManager
            // 判斷最后一個(gè)是否繪制红符,垂直青柄,判斷是否是最后一行,水平,直接返回true预侯,不繪制底部
            return ((LinearLayoutManager) layoutManager).getOrientation() != LinearLayout.VERTICAL || currentPosition == adapterCount - getFooterCount() - 1;
        } else if (layoutManager instanceof StaggeredGridLayoutManager) {
            // StaggeredGridLayoutManager
            // 判斷最后一個(gè)是否繪制致开,垂直,都顯示萎馅,返回false双戳, 水平,判斷是否是最后一列糜芳,是返回true
            StaggeredGridLayoutManager.LayoutParams lp = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
            return ((StaggeredGridLayoutManager) layoutManager).getOrientation() != StaggeredGridLayoutManager.VERTICAL && (lp.getSpanIndex() + 1) % spanCount == 0;
        }
        return false;
    }

    /**
     * 繪制水平線
     *
     * @param canvas     畫布
     * @param parent     RecyclerView
     * @param lineWidth  線寬
     * @param lineHeight 線高
     */
    private void drawHorizontal(Canvas canvas, RecyclerView parent, int lineWidth, int lineHeight) {
        boolean isDrawDoubleLine = false;
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof StaggeredGridLayoutManager && ((StaggeredGridLayoutManager) layoutManager).getOrientation() == StaggeredGridLayoutManager.HORIZONTAL)
            // 繪制雙線
            isDrawDoubleLine = true;
        canvas.save();
        int spanCount = getSpanCount(parent);// 水平個(gè)數(shù)飒货,線性布局為-1
        int childCount = parent.getChildCount();// 顯示的個(gè)數(shù)
        int adapterCount = parent.getAdapter().getItemCount();// 總個(gè)數(shù)
        if (parent.getClipToPadding()) {
            canvas.clipRect(parent.getPaddingLeft(), parent.getPaddingTop(),
                    parent.getWidth() - parent.getPaddingRight(),
                    parent.getHeight() - parent.getPaddingBottom());
        }

        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            int currentPosition = parent.getChildAdapterPosition(child);
            if (isSkipDraw(parent, child))
                // 跳過(guò)魄衅,直接返回
                continue;
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
            if (!isNotDrawBottom(child, parent, currentPosition, spanCount, adapterCount)) {
                // 繪制底部
                int bottomLineWidth = isNotDrawRight(child, parent, currentPosition, spanCount, adapterCount) ? 0 : lineWidth;// 不繪制右部,公共區(qū)域不繪制
                // 繪制下線
                final int downLeft = child.getLeft() - params.leftMargin;
                final int downTop = child.getBottom() + params.bottomMargin;
                final int downRight = child.getRight() + params.rightMargin + bottomLineWidth;// 公共區(qū)域繪制
                final int downBottom = downTop + lineHeight;
                dividerDrawable.setBounds(downLeft, downTop, downRight, downBottom);
                dividerDrawable.draw(canvas);
            }
            // 判斷是否繪制雙線
            if (isDrawDoubleLine && isStaggeredGridNotFirstView(child, spanCount)) {
                // 繪制上線
                final int upLeft = child.getLeft() - params.leftMargin;
                final int upTop = child.getTop() + params.topMargin - lineHeight;
                final int upRight = child.getRight() + params.rightMargin + lineWidth;// 公共區(qū)域繪制
                final int upBottom = upTop + lineHeight;
                dividerDrawable.setBounds(upLeft, upTop, upRight, upBottom);
                dividerDrawable.draw(canvas);
            }
        }
        canvas.restore();
    }

    /**
     * 繪制垂直線
     *
     * @param canvas     畫布
     * @param parent     RecyclerView
     * @param lineWidth  線寬
     * @param lineHeight 線高
     */
    private void drawVertical(Canvas canvas, RecyclerView parent, int lineWidth, int lineHeight) {
        boolean isDrawDoubleLine = false;
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof StaggeredGridLayoutManager && ((StaggeredGridLayoutManager) layoutManager).getOrientation() == StaggeredGridLayoutManager.VERTICAL)
            // 繪制雙線
            isDrawDoubleLine = true;
        canvas.save();
        if (parent.getClipToPadding()) {
            canvas.clipRect(parent.getPaddingLeft(), parent.getPaddingTop(),
                    parent.getWidth() - parent.getPaddingRight(),
                    parent.getHeight() - parent.getPaddingBottom());
        }
        int spanCount = getSpanCount(parent);// 水平個(gè)數(shù)塘辅,線性布局為-1
        int childCount = parent.getChildCount();
        int adapterCount = parent.getAdapter().getItemCount();// 總個(gè)數(shù)
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            int currentPosition = parent.getChildAdapterPosition(child);
            if (isSkipDraw(parent, child))
                // 跳過(guò)晃虫、不繪制右部,直接返回
                continue;
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
            if (!isNotDrawRight(child, parent, currentPosition, spanCount, adapterCount)) {
                // 不繪制右邊
                if (isNotDrawBottom(child, parent, currentPosition, spanCount, adapterCount))
                    // 不繪制底部扣墩,公共區(qū)域不繪制
                    lineHeight = 0;
                final int left = child.getRight() + params.rightMargin;
                final int top = child.getTop() - params.topMargin;
                final int right = left + lineWidth;
                final int bottom = child.getBottom() + params.bottomMargin + lineHeight;// 公共區(qū)域水平繪制
                dividerDrawable.setBounds(left, top, right, bottom);
                dividerDrawable.draw(canvas);
            }
            // 判斷是否繪制雙線
            if (isDrawDoubleLine && isStaggeredGridNotFirstView(child, spanCount)) {
                // 繪制左線
                final int left = child.getLeft() + params.leftMargin - lineWidth;
                final int top = child.getTop() - params.topMargin;
                final int right = left + lineWidth;
                final int bottom = child.getBottom() + params.bottomMargin + lineHeight;// 公共區(qū)域水平繪制
                dividerDrawable.setBounds(left, top, right, bottom);
                dividerDrawable.draw(canvas);
            }
        }
        canvas.restore();
    }

    /**
     * 是否是StaggeredGridLayoutManager的中間的view
     *
     * @param view      測(cè)定的view
     * @param spanCount 列數(shù)
     */
    private boolean isStaggeredGridNotFirstView(View view, int spanCount) {
        StaggeredGridLayoutManager.LayoutParams lp = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
        return lp.getSpanIndex() != 0;
    }

    /**
     * 是否跳過(guò)繪畫
     *
     * @param parent RecyclerView
     * @param view   當(dāng)前View
     */
    private boolean isSkipDraw(RecyclerView parent, View view) {
        int currentPosition = parent.getChildAdapterPosition(view);// 當(dāng)前item總位置
        int adapterCount = parent.getAdapter().getItemCount();
        return currentPosition < getHeaderCount() || currentPosition >= adapterCount - getFooterCount();
    }

    /**
     * 獲取列數(shù)
     *
     * @param parent RecyclerView
     * @return 列數(shù)
     */
    private int getSpanCount(RecyclerView parent) {
        // 列數(shù)
        int spanCount = -1;
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {
            spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
        } else if (layoutManager instanceof LinearLayoutManager) {
            spanCount = 1;
        } else if (layoutManager instanceof StaggeredGridLayoutManager) {
            spanCount = ((StaggeredGridLayoutManager) layoutManager).getSpanCount();
        }
        return spanCount;
    }

    /**
     * 獲取線寬
     */
    public int getLineWidth() {
        return lineWidth;
    }

    /**
     * 設(shè)置線寬
     */
    public void setLineWidth(int lineWidth) {
        this.lineWidth = lineWidth;
    }

    /**
     * 獲取線高
     */
    public int getLineHeight() {
        return lineHeight;
    }

    /**
     * 設(shè)置線高
     */
    public void setLineHeight(int lineHeight) {
        this.lineHeight = lineHeight;
    }

    /**
     * 獲取線Drawable
     */
    public Drawable getDividerDrawable() {
        return dividerDrawable;
    }

    /**
     * 設(shè)置線Drawable哲银,和setLineColor()二選一
     */
    public void setDividerDrawable(Drawable dividerDrawable) {
        this.dividerDrawable = dividerDrawable;
    }

    /**
     * 設(shè)置線顏色,和setDividerDrawable()二選一
     */
    public void setLineColor(int lineColor) {
        this.dividerDrawable = new ColorDrawable(lineColor);
    }

    /**
     * 獲取頭數(shù)量
     */
    private int getHeaderCount() {
        return headerCount;
    }

    /**
     * 設(shè)置頭數(shù)量呻惕,即頭部跳過(guò)繪制
     */
    public void setHeaderCount(int headerCount) {
        this.headerCount = headerCount;
    }

    /**
     * 獲取尾數(shù)量
     */
    private int getFooterCount() {
        return footerCount;
    }

    /**
     * 設(shè)置尾數(shù)量荆责,即尾部跳過(guò)繪制
     */
    public void setFooterCount(int footerCount) {
        this.footerCount = footerCount;
    }

    /**
     * Divider的構(gòu)建者
     */
    public static Builder builder() {
        return new Builder();
    }

    public static class Builder {

        private final Divider divider;

        Builder() {
            divider = new Divider();
        }

        /**
         * 設(shè)置線寬
         */
        public Builder width(int lineWidth) {
            divider.setLineWidth(lineWidth);
            return this;
        }

        /**
         * 設(shè)置線高
         */
        public Builder height(int lineHeight) {
            divider.setLineHeight(lineHeight);
            return this;
        }

        /**
         * 同時(shí)設(shè)置線寬、線高
         */
        public Builder widthAndHeight(int lineSize) {
            divider.setLineWidth(lineSize);
            divider.setLineHeight(lineSize);
            return this;
        }

        /**
         * 設(shè)置線顏色亚脆,和drawable二選一
         */
        public Builder color(int lineColor) {
            divider.setLineColor(lineColor);
            return this;
        }

        /**
         * 設(shè)置線背景做院,和color二選一
         */
        public Builder drawable(Drawable dividerDrawable) {
            divider.setDividerDrawable(dividerDrawable);
            return this;
        }

        /**
         * 設(shè)置頭的數(shù)量
         */
        public Builder headerCount(int headerCount) {
            divider.setHeaderCount(headerCount);
            return this;
        }

        /**
         * 設(shè)置尾的數(shù)量
         */
        public Builder footerCount(int footerCount) {
            divider.setFooterCount(footerCount);
            return this;
        }

        /**
         * 返回Divider
         */
        public Divider build() {
            return this.divider;
        }

    }
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市濒持,隨后出現(xiàn)的幾起案子山憨,更是在濱河造成了極大的恐慌,老刑警劉巖弥喉,帶你破解...
    沈念sama閱讀 221,576評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異玛迄,居然都是意外死亡由境,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門蓖议,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)虏杰,“玉大人,你說(shuō)我怎么就攤上這事勒虾》睦” “怎么了?”我有些...
    開封第一講書人閱讀 168,017評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵修然,是天一觀的道長(zhǎng)笛钝。 經(jīng)常有香客問(wèn)我,道長(zhǎng)愕宋,這世上最難降的妖魔是什么玻靡? 我笑而不...
    開封第一講書人閱讀 59,626評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮中贝,結(jié)果婚禮上囤捻,老公的妹妹穿的比我還像新娘。我一直安慰自己邻寿,他們只是感情好蝎土,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評(píng)論 6 397
  • 文/花漫 我一把揭開白布视哑。 她就那樣靜靜地躺著,像睡著了一般誊涯。 火紅的嫁衣襯著肌膚如雪挡毅。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,255評(píng)論 1 308
  • 那天醋拧,我揣著相機(jī)與錄音慷嗜,去河邊找鬼。 笑死丹壕,一個(gè)胖子當(dāng)著我的面吹牛庆械,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播菌赖,決...
    沈念sama閱讀 40,825評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼缭乘,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了琉用?” 一聲冷哼從身側(cè)響起堕绩,我...
    開封第一講書人閱讀 39,729評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎邑时,沒(méi)想到半個(gè)月后奴紧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,271評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡晶丘,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評(píng)論 3 340
  • 正文 我和宋清朗相戀三年黍氮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片浅浮。...
    茶點(diǎn)故事閱讀 40,498評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡沫浆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出滚秩,到底是詐尸還是另有隱情专执,我是刑警寧澤,帶...
    沈念sama閱讀 36,183評(píng)論 5 350
  • 正文 年R本政府宣布郁油,位于F島的核電站本股,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏已艰。R本人自食惡果不足惜痊末,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望哩掺。 院中可真熱鬧凿叠,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至炒刁,卻和暖如春恩沽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背翔始。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工罗心, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人城瞎。 一個(gè)月前我還...
    沈念sama閱讀 48,906評(píng)論 3 376
  • 正文 我出身青樓渤闷,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親脖镀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子飒箭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,280評(píng)論 25 707
  • 用兩張圖告訴你,為什么你的 App 會(huì)卡頓? - Android - 掘金 Cover 有什么料蜒灰? 從這篇文章中你...
    hw1212閱讀 12,744評(píng)論 2 59
  • 目錄介紹 1.RecycleView的結(jié)構(gòu) 2.Adapter2.1 RecyclerView.Adapter扮演...
    楊充211閱讀 3,102評(píng)論 3 17
  • 熱汽盈盈蒙上毛玻璃窗兒 腫脹的腦子在沸點(diǎn)邊緣 點(diǎn)子似熟非熟泛著油光 這鍋想法估摸要糊 煮著白溜溜的肉兒 覬覦的卻是...
    長(zhǎng)舌婦閱讀 407評(píng)論 3 0
  • 我們需要開始學(xué)習(xí)控制語(yǔ)句弦蹂,控制語(yǔ)句分為兩類:選擇和循環(huán)。 “選擇結(jié)構(gòu)”代表“如果…,則…”的邏輯强窖。 比如凸椿,如果女朋...
    全棧JAVA筆記閱讀 361評(píng)論 0 2