open class SpaceItemDecoration protected constructor() : RecyclerView.ItemDecoration() {
protected var mainWidth = 0
protected var crossWidth = 0
protected var mainPadding = 0
protected var crossPadding = 0
protected var ignorePredict: IgnorePredict? = null
open class Builder {
protected open val itemDecoration: SpaceItemDecoration = SpaceItemDecoration()
fun dividerWidth(mainWidth: Int, crossWidth: Int): Builder {
itemDecoration.mainWidth = mainWidth
itemDecoration.crossWidth = crossWidth
return this
}
fun padding(mainPadding: Int, crossPadding: Int): Builder {
itemDecoration.mainPadding = mainPadding
itemDecoration.crossPadding = crossPadding
return this
}
fun ignore(predict: IgnorePredict?): Builder {
itemDecoration.ignorePredict = predict
return this
}
fun build(): RecyclerView.ItemDecoration {
return itemDecoration
}
}
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
val manager = parent.layoutManager
val adapter = parent.adapter ?: return
val size = adapter.itemCount
val position = parent.getChildAdapterPosition(view)
if (position == RecyclerView.NO_POSITION) return
if (ignorePredict != null) {
if (ignorePredict!!.ignore(position)) {
return
}
}
if (manager is LinearLayoutManager) {
val isVertical = manager.orientation == LinearLayoutManager.VERTICAL
if (manager is GridLayoutManager) {
val spanCount = manager.spanCount
val spanSize = manager.spanSizeLookup.getSpanSize(position)
val spanIndex = manager.spanSizeLookup.getSpanIndex(position, spanCount)
val groupIndex = manager.spanSizeLookup.getSpanGroupIndex(position, spanCount)
val lastGroupIndex = manager.spanSizeLookup.getSpanGroupIndex(size - 1, spanCount)
getItemMainOffsets(outRect, isVertical, groupIndex == 0, groupIndex == lastGroupIndex)
getItemCrossOffsets(outRect, isVertical, spanCount, spanIndex, spanSize)
return
}
getItemMainOffsets(outRect, isVertical, position == 0, position == size - 1)
if (isVertical) {
outRect.left = crossPadding
outRect.right = crossPadding
} else {
outRect.top = crossPadding
outRect.bottom = crossPadding
}
} else if (manager is StaggeredGridLayoutManager) {
val isVertical = manager.orientation == StaggeredGridLayoutManager.VERTICAL
val lp = view.layoutParams
if (lp is StaggeredGridLayoutManager.LayoutParams) {
val spanCount = manager.spanCount
val exceptSpanIndex = position % spanCount
val spanIndex = lp.spanIndex
val isFirstGroup = position < spanCount && exceptSpanIndex == spanIndex
var isLastGroup = false
if (size - position <= spanCount) {
val lastItemView = manager.findViewByPosition(size - 1)
if (lastItemView != null) {
val lastLp = lastItemView.layoutParams
if (lastLp is StaggeredGridLayoutManager.LayoutParams) {
if (lastLp.spanIndex - spanIndex == size - 1 - position) {
isLastGroup = true
}
}
}
}
val spanSize = if (lp.isFullSpan) spanCount else 1
getItemMainOffsets(outRect, isVertical, isFirstGroup, isLastGroup)
getItemCrossOffsets(outRect, isVertical, spanCount, spanIndex, spanSize)
}
}
}
private fun getItemMainOffsets(outRect: Rect, isVertical: Boolean, isFirstGroup: Boolean, isLastGroup: Boolean) {
if (isFirstGroup) {
if (isVertical) {
outRect.top = mainPadding
} else {
outRect.left = mainPadding
}
} else if (isLastGroup) {
if (isVertical) {
outRect.top = mainWidth
outRect.bottom = mainPadding
} else {
outRect.left = mainWidth
outRect.right = mainPadding
}
} else {
if (isVertical) {
outRect.top = mainWidth
} else {
outRect.left = mainWidth
}
}
}
private fun getItemCrossOffsets(outRect: Rect, isVertical: Boolean, spanCount: Int, spanIndex: Int, spanSize: Int) {
val spanUsedWidth = (crossPadding * 2 + crossWidth * (spanCount - 1)) / spanCount
val lt = crossWidth * spanIndex + crossPadding - spanUsedWidth * spanIndex
val rb = spanUsedWidth * spanSize - crossWidth * (spanSize - 1) - lt
if (isVertical) {
outRect.left = lt
outRect.right = rb
} else {
outRect.top = lt
outRect.bottom = rb
}
}
interface IgnorePredict {
fun ignore(position: Int): Boolean
}
}
使用
recyclerView.addItemDecoration(
SpaceItemDecoration.Builder()
.dividerWidth(30, 20)
.padding(20, 30)
.build()
)
转自:写一个万用RecyclerView分隔线,支持linear grid staggered
GitHub地址