RecyclerView之間隔線

1,系統(tǒng)自帶的間割線

系統(tǒng)自帶的間割線實(shí)現(xiàn)方法很簡(jiǎn)單,看下面的代碼:

     rv_content.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
     rv_content.adapter = rcAdapter
     rv_content.addItemDecoration(DividerItemDecoration(this, DividerItemDecoration.VERTICAL)) 

這樣就實(shí)現(xiàn)了間割線的添加,效果如下:

device-2017-06-23-171259.png

上面的效果,是將方向設(shè)置為:LinearLayoutManager.VERTICAL,那么將方向設(shè)置為LinearLayoutManager.HORIZONTAL,此時(shí)效果為:

device-2017-06-23-171206.png

上面的顯示方式為LinearLayoutManager,那么將顯示方式設(shè)置為GridLayoutManager時(shí),也就是:

rv_content.layoutManager = GridLayoutManager(this, 3,GridLayoutManager.VERTICAL, false)

此時(shí)的效果為:

device-2017-06-23-171637.png

此時(shí),應(yīng)該察覺(jué)到,系統(tǒng)提供的間隔線類DividerItemDecoration只能適用于一些簡(jiǎn)單的情形。當(dāng)布局復(fù)雜時(shí),系統(tǒng)的間隔線就不能滿足我們的要求了,此時(shí)我們就要自己動(dòng)手來(lái)寫一個(gè)自己的間隔線或者使用第三方的間隔線。

2, 自定義間隔線

通過(guò)閱讀代碼,我們可以發(fā)現(xiàn)系統(tǒng)間割線DividerItemDecoration是繼承RecyclerView.ItemDecoration并實(shí)現(xiàn)了onDraw()getItemOffsets()方法 。
那么我們照著DividerItemDecoration來(lái)寫自己的間隔線類MyItemDecoration,代碼如下:

class MyItemDecoration(context: Context) : RecyclerView.ItemDecoration(){
    private var mOrientation: Int? = null
    private var dividerLine: Drawable? = null

    init {
        val typedArray = context.obtainStyledAttributes(ATTRS)
        dividerLine = typedArray!!.getDrawable(0)
        typedArray.recycle()
    }

    override fun onDraw(c: Canvas?, parent: RecyclerView?, state: RecyclerView.State?) {
        drawHorizontalLine(c, parent, state)
        drawVerticalLine(c, parent, state)
    }

    override fun getItemOffsets(outRect: Rect?, view: View?, parent: RecyclerView?, state: RecyclerView.State?) {
        val spanCount = getSpanCount(parent)
        val childCount = parent!!.adapter.itemCount
        val itemPosition = ((view!!.layoutParams)as RecyclerView.LayoutParams).viewLayoutPosition
        if (isLastRow(parent, itemPosition, spanCount, childCount)){
            outRect!!.set(0, 0, dividerLine!!.intrinsicWidth, 0)
        }else if (isLastColum(parent, itemPosition, spanCount, childCount)){
            outRect!!.set(0, 0, 0, dividerLine!!.intrinsicHeight)
        }else{
            outRect!!.set(0, 0, dividerLine!!.intrinsicWidth, dividerLine!!.intrinsicHeight)
        }

    }

    /**
     * 畫豎線
     */
    private fun  drawVerticalLine(c: Canvas?, parent: RecyclerView?, state: RecyclerView.State?) {
        for (i in 0..(parent!!.childCount - 1)){
            val child: View = parent.getChildAt(i)

            //獲取child布局參數(shù)
            val params: RecyclerView.LayoutParams = child.layoutParams as RecyclerView.LayoutParams
            val left = child.right + params.rightMargin
            val right = left + dividerLine!!.intrinsicWidth
            val top = child.top - params.topMargin
            val bottom = child.bottom + params.bottomMargin
            dividerLine!!.setBounds(left, top, right, bottom)
            dividerLine!!.draw(c)
        }
    }

    /**
     * 畫橫線
     */
    private fun  drawHorizontalLine(c: Canvas?, parent: RecyclerView?, state: RecyclerView.State?) {
        for (i in 0..(parent!!.childCount - 1)){
            val child: View = parent.getChildAt(i)

            val params: RecyclerView.LayoutParams = child.layoutParams as RecyclerView.LayoutParams
            val left = child.left - params.leftMargin
            val right = child.right + params.rightMargin+ dividerLine!!.intrinsicWidth
            val top = child.bottom + params.bottomMargin
            val bottom = top + dividerLine!!.intrinsicHeight
            dividerLine!!.setBounds(left, top, right, bottom)
            dividerLine!!.draw(c)
        }
    }

    /**
     * 獲取列數(shù)
     */
    private fun getSpanCount(parent: RecyclerView?): Int{
        var spanCount: Int = -1
        val layoutManager: RecyclerView.LayoutManager = parent!!.layoutManager
        if (layoutManager is GridLayoutManager){
            spanCount = layoutManager.spanCount
        }else if(layoutManager is StaggeredGridLayoutManager){
            spanCount = layoutManager.spanCount
        }
        return spanCount
    }

    /**
     * 判定是否為最后一列
     */
    private fun isLastColum(parent: RecyclerView?, pos: Int, spanCount: Int, childCount: Int): Boolean{
        val layoutManager: RecyclerView.LayoutManager = parent!!.layoutManager
        if (layoutManager is GridLayoutManager){
            if ((pos + 1)% spanCount == 0) {//如果是最后一列,則不在繪制右邊
                return true
            }
        }else if(layoutManager is StaggeredGridLayoutManager){
            val orientation = layoutManager.orientation
            if (orientation == StaggeredGridLayoutManager.VERTICAL){
                if ((pos + 1)% spanCount == 0) {//如果是最后一列,則不在繪制右邊
                    return true
                }
            }else{
                val childNum = childCount - childCount % spanCount
                if (pos >= childNum) {
                    return true
                }
            }
        }
        return false
    }

    /**
     * 判定是否為最后一行
     */
    private fun isLastRow(parent: RecyclerView?, pos: Int, spanCount: Int, childCount: Int): Boolean{
        val layoutManager: RecyclerView.LayoutManager = parent!!.layoutManager
        if (layoutManager is GridLayoutManager){
            val childNum = if(childCount % spanCount == 0) childCount - spanCount else childCount - childCount % spanCount
            if (pos >= childNum) {//如果是最后一行,則不在繪制底邊
                return true
            }
        }else if(layoutManager is StaggeredGridLayoutManager){
            val orientation = layoutManager.orientation
            if (orientation == StaggeredGridLayoutManager.VERTICAL){//縱向滾動(dòng)
                val childNum = childCount - childCount % spanCount
                if (pos >= childNum) {//如果是最后一行,則不在繪制底邊
                    return true
                }
            }else{//橫向滾動(dòng)
                if ((pos + 1) % spanCount == 0) {
                    return true
                }
            }
        }
        return false
    }

    companion object{
        private var ATTRS = intArrayOf(android.R.attr.listDivider)
    }
}

運(yùn)行程序,看效果圖為:

device-2017-06-23-182642.png

3,第三方分割線

請(qǐng)參考:
github地址:[Y_DividerItemDecoration]:(https://github.com/yanyusong/Y_DividerItemDecoration)
下面來(lái)看看對(duì)這個(gè)第三方j(luò)ar包的簡(jiǎn)單使用示例:

device-2017-06-24-124008.png

實(shí)現(xiàn)這個(gè)效果也很簡(jiǎn)單,代碼為:

class RecyclerViewNewListDividerActivity: BaseKotlinActivity(){
    private var mAdapter: Y_MultiRecyclerAdapter? = null
    private var y_ItemEntityList: Y_ItemEntityList? = null
    private var context: Context  = this

    override fun getLayoutResoucesId(): Int {
        return R.layout.activity_recycler_view_simple
    }

    override fun init() {
        y_ItemEntityList = Y_ItemEntityList()

        initToolBarScroll()

        y_ItemEntityList!!.addItems(R.layout.item_rc_4st, itemList).addOnBind(R.layout.item_rc_4st
                , object : Y_OnBind<String>{
            override fun onBindChildViewData(holder: GeneralRecyclerViewHolder?, itemData: String?, position: Int) {
                holder!!.setText(R.id.tv, itemData)
            }

        })

        rv_content.layoutManager = GridLayoutManager(this, 2, GridLayoutManager.VERTICAL, false)//設(shè)置顯示方式--瀑布流
        mAdapter = Y_MultiRecyclerAdapter(this, y_ItemEntityList)
        rv_content.adapter = mAdapter
        /**
         * 第三方----子項(xiàng)之間的分割線位置
         */
        rv_content.addItemDecoration(MyDividerItemDecoration(this))
        mAdapter!!.setOnItemClickListener { position -> showToast("onClick-->"+ position) }

    }

    private fun initToolBarScroll() {
        val param: AppBarLayout.LayoutParams = tb_toolbar.layoutParams as AppBarLayout.LayoutParams

        param.scrollFlags = AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL or AppBarLayout.LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED
    }

    class MyDividerItemDecoration(val context: Context): Y_DividerItemDecoration(context) {
        override fun getDivider(itemPosition: Int): Y_Divider {
            var divider: Y_Divider? = null
            when(itemPosition) {
                else -> {
                    /**
                     * 設(shè)置底部線
                     * setBottomSideLine(boolean isHave, @ColorInt int color, float widthDp, float startPaddingDp, float endPaddingDp)
                     *  isHave:true 顯示線;false 不顯示
                     *  color:線的顏色。@ColorInt int color 表示這里需要的是一個(gè)顏色值,而不是顏色id。因此直接使用R.color.XXX是不行的,可以通過(guò)ContextCompat.getColor(context, R.color.black)來(lái)獲取
                     *  widthDp:線的高度
                     *  startPaddingDp:距離左邊多少dp開(kāi)始畫線
                     *  endPaddingDp:距離右邊多少dp停止畫線
                     */
                    val count = if(itemList.size%2==0) itemList.size - 2 else itemList.size - itemList.size%2
                    if (itemPosition >= count){
                        if (itemPosition % 2 == 0){
                            divider = Y_DividerBuilder().setRightSideLine(true, ContextCompat.getColor(context, R.color.colorAccent), 2F, 0F, 0F)
                                    .create()
                        }else{
                            divider = Y_DividerBuilder().setBottomSideLine(true, ContextCompat.getColor(context, R.color.trans), 2F, 0F, 0F).create()
                        }
                    }else{
                        if (itemPosition % 2 == 0){
                            divider = Y_DividerBuilder().setRightSideLine(true, ContextCompat.getColor(context, R.color.colorAccent), 2F, 0F, 0F)
                                    .setBottomSideLine(true, ContextCompat.getColor(context, R.color.black), 2F, 0F, 0F).create()
                        }else{
                            divider = Y_DividerBuilder().setBottomSideLine(true, ContextCompat.getColor(context, R.color.black), 2F, 0F, 0F).create()
                        }
                    }
                }
            }
            return divider!!
        }

    }
    companion object{
        //    private val itemList = listOf("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "W", "X", "Y", "Z", "Z")
       private val itemList = listOf("a", "b", "c", "d", "e")
    }
}

上面這個(gè)效果的關(guān)鍵代碼都在Y_DividerItemDecoration類的getDivider方法中,這個(gè)jar包中,給提供了設(shè)置上下左右線的方法,使用起來(lái)并不復(fù)雜。
在看下圖效果:

device-2017-06-24-133854.png

這個(gè)效果實(shí)現(xiàn)的關(guān)鍵就是每行的列數(shù),有1列的,2列的,3列的,4列的幾種,看列數(shù)獲取的方法:

/**
         * 這里的“12”總共的列數(shù),因?yàn)椴季至袛?shù)不定,有1,2,3,4幾種,這樣只有取得它們的公倍數(shù),才能使計(jì)算方便
         */
        val layoutManager = GridLayoutManager(this, 12, GridLayoutManager.VERTICAL, false)//設(shè)置顯示方式
        layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup(){
            override fun getSpanSize(position: Int): Int {
                if (position == 0 || position == 1) {
                    return 6
                } else if (position == 6 || position == 10) {
                    return 12
                } else if (position in 7..9) {
                    return 4
                } else if (position in 2..5) {
                    return 3
                }
                return 3
            }
        }
        rv_content.layoutManager = layoutManager

getDivider方法的實(shí)現(xiàn):

class MyNewDividerItemDecoration(val context: Context): Y_DividerItemDecoration(context) {
        override fun getDivider(itemPosition: Int): Y_Divider {
            var divider: Y_Divider? = null
            if (itemPosition in 1..6 || itemPosition == 9 || itemPosition == 10) {
                divider = Y_DividerBuilder()
                        .setBottomSideLine(true, ContextCompat.getColor(context, R.color.colorAccent), 2f, 0f, 0f)
                        .create()
            } else if (itemPosition == 0 || itemPosition == 7 || itemPosition == 8) {
                divider = Y_DividerBuilder()
                        .setRightSideLine(true, ContextCompat.getColor(context, R.color.black), 2f, 0f, 0f)
                        .setBottomSideLine(true, ContextCompat.getColor(context, R.color.colorAccent), 2f, 0f, 0f)
                        .create()
            } else if (itemPosition in 11..21) {

                when ((itemPosition - 10) % 4) {
                    1, 2, 3 -> {
                        divider = Y_DividerBuilder()
                                .setRightSideLine(true, ContextCompat.getColor(context, R.color.black), 2f, 0f, 0f)
                                .setBottomSideLine(true, ContextCompat.getColor(context, R.color.colorAccent), 2f, 0f, 0f)
                                .create()
                    }
                    0 -> {
                        divider = Y_DividerBuilder()
                                .setBottomSideLine(true, ContextCompat.getColor(context, R.color.colorAccent), 2f, 0f, 0f)
                                .create()
                    }
                    else -> {
                        divider = Y_DividerBuilder().setBottomSideLine(true, ContextCompat.getColor(context, R.color.trans), 2F, 0F, 0F).create()
                    }
                }
            }
            return divider!!
        }

    }

關(guān)于RecyclerView的分割線,下一篇寫RecyclerView的條目動(dòng)畫

參考文檔

1,[Android RecyclerView 使用完全解析 體驗(yàn)藝術(shù)般的控件]:http://blog.csdn.net/lmj623565791/article/details/45059587
2,間隔線第三方github地址:[Y_DividerItemDecoration]:https://github.com/yanyusong/Y_DividerItemDecoration

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,777評(píng)論 25 709
  • 1 霓虹初上,喧鬧間歇,漸逝的歲月里是否還像往昔一樣笑容依舊? 本是一個(gè)安靜的過(guò)客,無(wú)奈沾染了紛亂的紅塵喧囂,欲讓...
    筆墨生閱讀 329評(píng)論 0 1
  • 書看完好久了,沒(méi)時(shí)間整理,快忘了,先上圖; 鏡像(image)類似于虛擬機(jī)鏡像,是創(chuàng)建容器的基礎(chǔ);鏡像是只讀的; ...
    小直閱讀 2,538評(píng)論 0 51
  • 1、完成晨跑10公里,收聽(tīng)《五分鐘商學(xué)院》。 2、完成份內(nèi)工作資料內(nèi)業(yè):完成對(duì)主體圍護(hù)結(jié)構(gòu)核算、上報(bào)施工情況及記錄...
    清風(fēng)_bd61閱讀 124評(píng)論 0 0
  • 工薪族能夠做到買寶馬嗎?好吧,今天我的母親就幫我做到了,為此,我決定寫一篇文來(lái)作為紀(jì)念。同時(shí),也是對(duì)母親的感激。 ...
    墨魚(yú)好奇寶寶閱讀 858評(píng)論 0 0

友情鏈接更多精彩內(nèi)容