一、前言
之前的方法在某些情况下使用会有问题,这个新的类适配了各种情况,可以在线下布局,网格布局,垂直,水平方向上都能实现很好的分隔效果。
二、使用方法详解
val build = IntervalItemDecoration.Builder()
.divider(space)//设置每个 item 之间的间距
// .dividerHorrizontal(space)//设置 item 左右间隔
// .dividerVertical(space)//设置 item 上下间隔
.margin(space)//设置 recyclerview 四周间隔
// .horriontalMargin(space)//设置 recyclerview 左右间隔
// .verticalMargin(space * 2)//设置 recyclerview上下间隔
// .leftMargin(space)//单独设置 recyclerview 左边间隔
// .rightMargin(space)//单独设置 recyclerview 右边间隔
// .topMargin(space)//单独设置 recyclerview 上边间隔
// .bottomMargin(space)//单独设置 recyclerview 下边间隔
.build()
三、详细代码和引入地址
class IntervalItemDecoration private constructor(private val builder: Builder) :
RecyclerView.ItemDecoration() {
//每个 item 上下左右两侧间隔
private var divider = 0
// 每个item左右两侧的间距
private var dividerHorrizontal = 0
// 每个item上下的间距
private var dividerVertical = 0
//整个 recyclerview 间距
private var margin = 0
//整个 recyclerview 左右间距
private var horriontalMargin = 0
//整个 recyclerview 上下间距
private var verticalMargin = 0
// 整个RecyclerView的左间距
private var leftMargin = 0
// 整个RecyclerView的顶部间距
private var topMargin = 0
// 整个RecyclerView的右间距
private var rightMargin = 0
// 整个RecyclerView的底部间距
private var bottomMargin = 0
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
super.getItemOffsets(outRect, view, parent, state)
// 得到当前Item在RecyclerView中的位置,从0开始
// 得到当前Item在RecyclerView中的位置,从0开始
val position = parent.getChildAdapterPosition(view)
// 得到RecyclerView中Item的总个数
// 得到RecyclerView中Item的总个数
val count = parent.adapter!!.itemCount
if (parent.layoutManager is GridLayoutManager) { // 网格布局
val gridLayoutManager =
parent.layoutManager as GridLayoutManager?
// 得到网格布局的列数
val spanCount = gridLayoutManager!!.spanCount
// 判断该网格布局是水平还是垂直
if (LinearLayoutManager.VERTICAL == gridLayoutManager.orientation) { // 垂直
if (spanCount == 1) { // 列数为1
verticalColumnOne(outRect, position, count)
} else { // 列数大于1
verticalColumnMulti(outRect, position, count, spanCount)
}
} else if (LinearLayoutManager.HORIZONTAL == gridLayoutManager.orientation) { // 水平
if (spanCount == 1) { // 行数为1
horizontalColumnOne(outRect, position, count)
} else { // 行数大于1
horizontalColumnMulti(outRect, position, count, spanCount)
}
}
} else if (parent.layoutManager is LinearLayoutManager) { // 线性布局
val layoutManager =
parent.layoutManager as LinearLayoutManager?
if (LinearLayoutManager.VERTICAL == layoutManager!!.orientation) { // 垂直
verticalColumnOne(outRect, position, count)
} else if (LinearLayoutManager.HORIZONTAL == layoutManager.orientation) { // 水平
horizontalColumnOne(outRect, position, count)
}
} else if (parent.layoutManager is StaggeredGridLayoutManager) { // 流布局
//TODO 瀑布流布局相关
}
}
/**
* 列表垂直且列数为1
*
* @param outRect 包括左上右下四个参数,分别控制view左上右下的margin
* @param position 当前view所处位置
* @param count RecyclerView中Item的总个数
*/
private fun verticalColumnOne(
outRect: Rect,
position: Int,
count: Int
) {
when (position) {
0 -> { // 位置为0时(即第一个Item),不设置底部间距
outRect[leftMargin, topMargin, rightMargin] = 0
}
count - 1 -> { // 最后一个Item
outRect[leftMargin, dividerVertical, rightMargin] = bottomMargin
}
else -> { // 中间的Item,不设置底部间距
outRect[leftMargin, dividerVertical, rightMargin] = 0
}
}
}
/**
* 列表垂直且列数大于1
*
* @param outRect 包括左上右下四个参数,分别控制view左上右下的margin
* @param position 当前view所处位置
* @param count RecyclerView中Item的总个数
* @param spanCount 布局的列数
*/
private fun verticalColumnMulti(
outRect: Rect,
position: Int,
count: Int,
spanCount: Int
) {
// 由于是网格布局,故每个item宽度是固定的,这里计算出每个item的左右边距之和
val mEachSpace: Int =
(leftMargin + rightMargin + (spanCount - 1) * dividerHorrizontal) / spanCount
// 通过计算得出总行数
val totalRow = count / spanCount + if (count % spanCount == 0) 0 else 1
// 计算得出当前view所在的行
val row = position / spanCount
val column = position % spanCount
val diff = (mEachSpace - rightMargin - leftMargin) / (spanCount - 1)
val left = (column + 1 - 1) * diff + leftMargin
val right = mEachSpace - left
when (row) {
0 -> {
outRect[left, topMargin, right] = dividerVertical
}
totalRow - 1 -> {
outRect[left, 0, right] = bottomMargin
}
else -> {
outRect[left, 0, right] = dividerVertical
}
}
}
/**
* 列表水平且行数为1
*
* @param outRect 包括左上右下四个参数,分别控制view左上右下的margin
* @param position 当前view所处位置
* @param count RecyclerView中Item的总个数
*/
private fun horizontalColumnOne(
outRect: Rect,
position: Int,
count: Int
) {
when (position) {
0 -> { // 位置为0时(即第一个Item)
outRect[leftMargin, topMargin, dividerHorrizontal / 2] = bottomMargin
}
count - 1 -> { // 最后一个Item
outRect[dividerHorrizontal / 2, topMargin, rightMargin] = bottomMargin
}
else -> { // 中间的Item
outRect[dividerHorrizontal / 2, topMargin, dividerHorrizontal / 2] = bottomMargin
}
}
}
/**
* 列表水平且行数大于1
*
* @param outRect 包括左上右下四个参数,分别控制view左上右下的margin
* @param position 当前view所处位置
* @param count RecyclerView中Item的总个数
* @param spanCount 布局的行数
*/
private fun horizontalColumnMulti(
outRect: Rect,
position: Int,
count: Int,
spanCount: Int
) {
// 通过计算得出总列数
val totalColumn = count / spanCount + if (count % spanCount == 0) 0 else 1
// 计算得出当前view所在的列
val column = position / spanCount
// 通过对position加1对spanCount取余得到row
// 保证row等于1为第一行,等于0为最后一个,其它值为中间行
val row = (position + 1) % spanCount
val mEachSpace: Int =
(topMargin + bottomMargin + (spanCount - 1) * dividerVertical) / spanCount
val diff = (mEachSpace - bottomMargin - topMargin) / (spanCount - 1)
val top = (position % spanCount + 1 - 1) * diff + topMargin
val bottom = mEachSpace - top
when (row) {
1 -> {
outRect[if (column == 0) leftMargin else dividerHorrizontal / 2, top, if (column == totalColumn - 1) rightMargin else dividerHorrizontal / 2] =
bottom
}
0 -> {
outRect[if (column == 0) leftMargin else dividerHorrizontal / 2, top, if (column == totalColumn - 1) rightMargin else dividerHorrizontal / 2] =
bottom
}
else -> {
outRect[if (column == 0) leftMargin else dividerHorrizontal / 2, top, if (column == totalColumn - 1) rightMargin else dividerHorrizontal / 2] =
bottom
}
}
}
class Builder {
private val iid = IntervalItemDecoration(this)
fun divider(divider: Int): Builder {
iid.divider = divider
return this
}
fun dividerHorrizontal(dividerHorrizontal: Int): Builder {
iid.dividerHorrizontal = dividerHorrizontal
return this
}
fun dividerVertical(dividerVertical: Int): Builder {
iid.dividerVertical = dividerVertical
return this
}
fun margin(margin: Int): Builder {
iid.margin = margin
return this
}
fun horriontalMargin(horriontalMargin: Int): Builder {
iid.horriontalMargin = horriontalMargin
return this
}
fun verticalMargin(verticalMargin: Int): Builder {
iid.verticalMargin = verticalMargin
return this
}
fun leftMargin(leftMargin: Int): Builder {
iid.leftMargin = leftMargin
return this
}
fun topMargin(topMargin: Int): Builder {
iid.topMargin = topMargin
return this
}
fun rightMargin(rightMargin: Int): Builder {
iid.rightMargin = rightMargin
return this
}
fun bottomMargin(bottomMargin: Int): Builder {
iid.bottomMargin = bottomMargin
return this
}
fun build(): IntervalItemDecoration {
initSet()
return iid
}
private fun initSet() {
iid.run {
if (divider != 0) {
dividerHorrizontal = divider
dividerVertical = divider
}
if (margin != 0) {
leftMargin = margin
rightMargin = margin
topMargin = margin
bottomMargin = margin
}
if (verticalMargin != 0) {
topMargin = verticalMargin
bottomMargin = verticalMargin
}
if (horriontalMargin != 0) {
leftMargin = horriontalMargin
rightMargin = horriontalMargin
}
}
}
}
}