RecyclerView之间隔线

1,系统自带的间割线

系统自带的间割线实现方法很简单,看下面的代码:

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

这样就实现了间割线的添加,效果如下:

device-2017-06-23-171259.png

上面的效果,是将方向设置为:LinearLayoutManager.VERTICAL,那么将方向设置为LinearLayoutManager.HORIZONTAL,此时效果为:

device-2017-06-23-171206.png

上面的显示方式为LinearLayoutManager,那么将显示方式设置为GridLayoutManager时,也就是:

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

此时的效果为:

device-2017-06-23-171637.png

此时,应该察觉到,系统提供的间隔线类DividerItemDecoration只能适用于一些简单的情形。当布局复杂时,系统的间隔线就不能满足我们的要求了,此时我们就要自己动手来写一个自己的间隔线或者使用第三方的间隔线。

2, 自定义间隔线

通过阅读代码,我们可以发现系统间割线DividerItemDecoration是继承RecyclerView.ItemDecoration并实现了onDraw()getItemOffsets()方法 。
那么我们照着DividerItemDecoration来写自己的间隔线类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布局参数
            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)
        }
    }

    /**
     * 获取列数
     */
    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){//纵向滚动
                val childNum = childCount - childCount % spanCount
                if (pos >= childNum) {//如果是最后一行,则不在绘制底边
                    return true
                }
            }else{//横向滚动
                if ((pos + 1) % spanCount == 0) {
                    return true
                }
            }
        }
        return false
    }

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

运行程序,看效果图为:

device-2017-06-23-182642.png

3,第三方分割线

请参考:
github地址:[Y_DividerItemDecoration]:(https://github.com/yanyusong/Y_DividerItemDecoration)
下面来看看对这个第三方jar包的简单使用示例:

device-2017-06-24-124008.png

实现这个效果也很简单,代码为:

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)//设置显示方式--瀑布流
        mAdapter = Y_MultiRecyclerAdapter(this, y_ItemEntityList)
        rv_content.adapter = mAdapter
        /**
         * 第三方----子项之间的分割线位置
         */
        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 -> {
                    /**
                     * 设置底部线
                     * setBottomSideLine(boolean isHave, @ColorInt int color, float widthDp, float startPaddingDp, float endPaddingDp)
                     *  isHave:true 显示线;false 不显示
                     *  color:线的颜色。@ColorInt int color 表示这里需要的是一个颜色值,而不是颜色id。因此直接使用R.color.XXX是不行的,可以通过ContextCompat.getColor(context, R.color.black)来获取
                     *  widthDp:线的高度
                     *  startPaddingDp:距离左边多少dp开始画线
                     *  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")
    }
}

上面这个效果的关键代码都在Y_DividerItemDecoration类的getDivider方法中,这个jar包中,给提供了设置上下左右线的方法,使用起来并不复杂。
在看下图效果:

device-2017-06-24-133854.png

这个效果实现的关键就是每行的列数,有1列的,2列的,3列的,4列的几种,看列数获取的方法:

/**
         * 这里的“12”总共的列数,因为布局列数不定,有1,2,3,4几种,这样只有取得它们的公倍数,才能使计算方便
         */
        val layoutManager = GridLayoutManager(this, 12, GridLayoutManager.VERTICAL, false)//设置显示方式
        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方法的实现:

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!!
        }

    }

关于RecyclerView的分割线,下一篇写RecyclerView的条目动画

参考文档

1,[Android RecyclerView 使用完全解析 体验艺术般的控件]:http://blog.csdn.net/lmj623565791/article/details/45059587
2,间隔线第三方github地址:[Y_DividerItemDecoration]:https://github.com/yanyusong/Y_DividerItemDecoration

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,376评论 25 707
  • 1 霓虹初上,喧闹间歇,渐逝的岁月里是否还像往昔一样笑容依旧? 本是一个安静的过客,无奈沾染了纷乱的红尘喧嚣,欲让...
    笔墨生阅读 230评论 0 1
  • 书看完好久了,没时间整理,快忘了,先上图; 镜像(image)类似于虚拟机镜像,是创建容器的基础;镜像是只读的; ...
    小直阅读 2,479评论 0 51
  • 1、完成晨跑10公里,收听《五分钟商学院》。 2、完成份内工作资料内业:完成对主体围护结构核算、上报施工情况及记录...
    清风_bd61阅读 90评论 0 0
  • 工薪族能够做到买宝马吗?好吧,今天我的母亲就帮我做到了,为此,我决定写一篇文来作为纪念。同时,也是对母亲的感激。 ...
    墨鱼好奇宝宝阅读 642评论 0 0