1,系统自带的间割线
系统自带的间割线实现方法很简单,看下面的代码:
rv_content.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
rv_content.adapter = rcAdapter
rv_content.addItemDecoration(DividerItemDecoration(this, DividerItemDecoration.VERTICAL))
这样就实现了间割线的添加,效果如下:
上面的效果,是将方向设置为:LinearLayoutManager.VERTICAL
,那么将方向设置为LinearLayoutManager.HORIZONTAL
,此时效果为:
上面的显示方式为LinearLayoutManager
,那么将显示方式设置为GridLayoutManager
时,也就是:
rv_content.layoutManager = GridLayoutManager(this, 3,GridLayoutManager.VERTICAL, false)
此时的效果为:
此时,应该察觉到,系统提供的间隔线类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)
}
}
运行程序,看效果图为:
3,第三方分割线
请参考:
github地址:[Y_DividerItemDecoration]:(https://github.com/yanyusong/Y_DividerItemDecoration)
下面来看看对这个第三方jar包的简单使用示例:
实现这个效果也很简单,代码为:
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包中,给提供了设置上下左右线的方法,使用起来并不复杂。
在看下图效果:
这个效果实现的关键就是每行的列数,有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