package com.tiger.tlasgnjlliation.utils
import android.graphics.Canvas
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.view.View
import androidx.annotation.DrawableRes
import androidx.annotation.IntDef
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.tiger.tlasgnjlliation.utils.RecyclerItemDecoration.Companion.ALL
import com.tiger.tlasgnjlliation.utils.RecyclerItemDecoration.Companion.INNER
import com.tiger.tlasgnjlliation.utils.RecyclerItemDecoration.Companion.OUTER
import kotlin.math.roundToInt
/**
* @param dividerResId 边框资源id
* @param showDivider 显示模式
* @see INNER
* item1 | item2 | ... | itemN
*
* item1 item1 | item2 | ... | itemM
* ------ --------------------------------------------
* item2 itemM + 1 | itemM + 2 | ... | item2M
* ------ --------------------------------------------
* . .
* . .
* . .
* ------ --------------------------------------------
* itemN itemM + N | itemM + 1 + N | ... | item2M + N
*
* @see ALL
* | item1 | item2 | ... | itemN |
*
* ------ --------------------------------------------
* item1 |item1 | item2 | ... | itemM |
* ----- |--------------------------------------------|
* item2 |itemM + 1 | itemM + 2 | ... | item2M |
* ----- |--------------------------------------------|
* . | . |
* . | . |
* . | . |
* ----- |--------------------------------------------|
* itemN |itemM + N | itemM + 1 + N | ... | item2M + N|
* ------ --------------------------------------------
*
* @see OUTER
* | item1 item2 ... itemN |
*
* ------ --------------------------------------------
* item1 |item1 item2 ... itemM |
* item2 |itemM + 1 itemM + 2 ... item2M |
* . | . |
* . | . |
* . | . |
* itemN |itemM + N itemM + 1 + N ... item2M + N|
* ------ --------------------------------------------
*/
class RecyclerItemDecoration(
@DrawableRes private val dividerResId: Int,
@ShowDivider private val showDivider: Int = INNER
) : RecyclerView.ItemDecoration() {
companion object {
const val INNER = -1
const val ALL = 0
const val OUTER = 1
}
@Retention(AnnotationRetention.SOURCE)
@IntDef(INNER, ALL, OUTER)
annotation class ShowDivider
private lateinit var mDivider: Drawable
private val mBounds = Rect()
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
if (parent.layoutManager == null) {
return
}
if (!::mDivider.isInitialized) {
mDivider = ContextCompat.getDrawable(parent.context, dividerResId)!!
}
drawVertical(c, parent)
}
private fun drawVertical(canvas: Canvas, parent: RecyclerView) {
canvas.save()
if (parent.clipToPadding) {
canvas.clipRect(
parent.paddingLeft, parent.paddingTop,
parent.width - parent.paddingRight,
parent.height - parent.paddingBottom
)
}
val childCount = parent.childCount
for (i in 0 until childCount) {
val child = parent.getChildAt(i)
parent.getDecoratedBoundsWithMargins(child, mBounds)
if (mBounds.left != child.left) {
val leftDividerLeft = mBounds.left + child.translationX.roundToInt()
val leftDividerRight = leftDividerLeft + mDivider.intrinsicHeight
mDivider.setBounds(leftDividerLeft, child.top, leftDividerRight, child.bottom)
mDivider.draw(canvas)
}
if (mBounds.top != child.top) {
val topDividerTop = mBounds.top + child.translationY.roundToInt()
val topDividerBottom = topDividerTop + mDivider.intrinsicHeight
mDivider.setBounds(child.left, topDividerTop, child.right, topDividerBottom)
mDivider.draw(canvas)
}
if (mBounds.right != child.right) {
val rightDividerRight = mBounds.right + child.translationX.roundToInt()
val rightDividerLeft = rightDividerRight - mDivider.intrinsicHeight
mDivider.setBounds(rightDividerLeft, child.top, rightDividerRight, child.bottom)
mDivider.draw(canvas)
}
if (mBounds.bottom != child.bottom) {
val bottomDividerBottom = mBounds.bottom + child.translationY.roundToInt()
val bottomDividerTop = bottomDividerBottom - mDivider.intrinsicHeight
mDivider.setBounds(child.left, bottomDividerTop, child.right, bottomDividerBottom)
mDivider.draw(canvas)
}
}
canvas.restore()
}
override fun getItemOffsets(
outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State
) {
if (!::mDivider.isInitialized) {
mDivider = ContextCompat.getDrawable(parent.context, dividerResId)!!
}
// 得到当前Item在RecyclerView中的位置,从0开始
val position = parent.getChildAdapterPosition(view)
// 得到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)
}
}
}
/**
* 列表垂直且列数为1
*
* @param outRect 包括左上右下四个参数,分别控制view左上右下的margin
* @param position 当前view所处位置
* @param count RecyclerView中Item的总个数
*/
private fun verticalColumnOne(outRect: Rect, position: Int, count: Int) {
when (showDivider) {
INNER -> {
if (position!= 0) outRect.top = mDivider.intrinsicHeight
}
ALL -> {
if (position== 0) outRect.top = mDivider.intrinsicHeight
outRect.bottom = mDivider.intrinsicHeight
}
OUTER -> {
if (position== 0) outRect.top = mDivider.intrinsicHeight
if (position== count- 1) outRect.bottom = mDivider.intrinsicHeight
}
}
}
/**
* 列表垂直且列数大于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) {
// 通过计算得出总行数
val totalRow = count/ spanCount+ if (count% spanCount== 0) 0 else 1
// 计算得出当前view所在的行
val row = position/ spanCount
// 通过对position加1对spanCount取余得到column,column等于1为第一列,等于0为最后一列
val column = (position+ 1) % spanCount
when (showDivider) {
INNER -> {
if (column != 0 && position!= count- 1) {
// 非最后一列且非最后一个
outRect.right = mDivider.intrinsicHeight
}
if (position+ spanCount< count) {
outRect.bottom = mDivider.intrinsicHeight
}
}
ALL -> {
outRect.right = mDivider.intrinsicHeight
outRect.bottom = mDivider.intrinsicHeight
if (column == 1) {
// 第一列
outRect.left = mDivider.intrinsicHeight
}
if (row == 0) {
// 第一行
outRect.top = mDivider.intrinsicHeight
}
}
OUTER -> {
if (column == 1) {
// 第一列
outRect.left = mDivider.intrinsicHeight
} else if (column == 0) {
// 最后一列
outRect.right = mDivider.intrinsicHeight
}
if (row == 0) {
// 第一行
outRect.top = mDivider.intrinsicHeight
} else if (row == totalRow - 1) {
// 最后一行
outRect.bottom = mDivider.intrinsicHeight
// 最后一行的个数
val excess = count% spanCount
if (excess != 0 && column == excess) {
// 当前为最后一行最后一列,把右边补足
outRect.right = mDivider.intrinsicHeight
}
}
if (position+ spanCount>= count) {
// 补足底边
outRect.bottom = mDivider.intrinsicHeight
}
}
}
}
/**
* 列表水平且行数为1
*
* @param outRect 包括左上右下四个参数,分别控制view左上右下的margin
* @param position 当前view所处位置
* @param count RecyclerView中Item的总个数
*/
private fun horizontalColumnOne(outRect: Rect, position: Int, count: Int) {
when (showDivider) {
INNER -> {
if (position!= 0) outRect.left = mDivider.intrinsicHeight
}
ALL -> {
if (position== 0) outRect.left = mDivider.intrinsicHeight
outRect.right = mDivider.intrinsicHeight
}
OUTER -> {
if (position== 0) outRect.left = mDivider.intrinsicHeight
if (position== count- 1) outRect.right = mDivider.intrinsicHeight
}
}
}
/**
* 列表水平且行数大于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
when (showDivider) {
INNER -> {
if (row != 0 && position!= count- 1) {
// 非最后一行且非最后一个
outRect.bottom = mDivider.intrinsicHeight
}
if (position+ spanCount< count) {
outRect.right = mDivider.intrinsicHeight
}
}
ALL -> {
outRect.right = mDivider.intrinsicHeight
outRect.bottom = mDivider.intrinsicHeight
if (row == 1) {
// 第一行
outRect.top = mDivider.intrinsicHeight
}
if (column == 0) {
// 第一列
outRect.left = mDivider.intrinsicHeight
}
}
OUTER -> {
if (row == 1) {
// 第一行
outRect.top = mDivider.intrinsicHeight
} else if (row == 0) {
// 最后一行
outRect.bottom = mDivider.intrinsicHeight
}
if (column == 0) {
// 第一列
outRect.left = mDivider.intrinsicHeight
} else if (column == totalColumn - 1) {
// 最后一列
outRect.right = mDivider.intrinsicHeight
// 最后一列的个数
val excess = count% spanCount
if (excess != 0 && row == excess) {
// 当前为最后一列最后一行,把底边补足
outRect.bottom = mDivider.intrinsicHeight
}
}
if (position+ spanCount>= count) {
// 补足右边
outRect.right = mDivider.intrinsicHeight
}
}
}
}
}