美文网首页自定义view
RecyclerView之间隔线

RecyclerView之间隔线

作者: 小和尚恋红尘 | 来源:发表于2017-06-26 17:31 被阅读62次

    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

    相关文章

      网友评论

        本文标题:RecyclerView之间隔线

        本文链接:https://www.haomeiwen.com/subject/pnfbqxtx.html