在
RecyclerView
中,可以使用
ItemDecoration
添加项目之间的间距。
在此之前,让我们进行一些数学计算,以找出列表项周围的边距。
在这里,我们得到了等距区域。在每个区域中,我们必须找到它们的边距并将其返回到
outRect
中。如果您正确地进行了数学计算,为了保持等距和等大小,您会发现这些偏移值不是常数,它们根据列索引和行索引而改变。让我们推导出偏移值的方程式。
带有外边缘
在第一种情况下,我们考虑边缘周围的边距。
![enter image description here](https://istack.dev59.com/Z3qgf.webp)
For 0 and 1,
d + w + a = d − a + w + c
c = 2a
For 0 and 2,
d + w + a = d − c + w + e
e = a + c
e = 3a
If you see the pattern here,
right = a, 2a, 3a, ... , (n + 1) × a
right = (nᵢ + 1) × a
na = d
a = d ÷ n
right = (nᵢ + 1) × d ÷ n
Pattern of left side,
left = d, d − a, d − 2a, d − 3a, ... , d − na
left = d − nᵢ × a
left = d − nᵢ × d ÷ n
nᵢ - Column index
没有外边缘
在这里,我们进行数学计算时不考虑边缘。
![enter image description here](https://istack.dev59.com/cEZK6.webp)
For 0 and 1,
w + a = d − a + w + c
c = 2a − d
For 0 and 2,
w + a = d − c + w + e
e = 3a − 2d
The pattern here is,
right = a, 2a − d, 3a − 2d, ... , (n + 1) × a - nd
right = (nᵢ + 1) × a - nᵢd
(n + 1) × a − nd = 0
a = nd ÷ (n + 1)
∴ right = d − d × (nᵢ + 1) ÷ q
q = n + 1
q - Column count
nᵢ - Column index
left = 0, d − a, 2(d − a), ... , n(d − a)
left = nᵢ(d − a)
left = nᵢ × d ÷ q
让我们为此编写代码...
class SpacingItemDecoration(
private val spacing: Int,
private val includeEdge: Boolean,
private val headerRowCount: Int = 0
) : RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
val columnCount = getColumnCount(parent)
val position = parent.getChildAdapterPosition(view) - headerRowCount * columnCount
if (position >= 0) {
val rowCount = getRowCount(parent, columnCount)
val orientation = getOrientation(parent)
val columnIndex = position % columnCount
val rowIndex = position / columnCount
if (includeEdge) {
when (orientation) {
RecyclerView.VERTICAL -> {
outRect.left = getStartOffsetWithEdge(spacing, columnIndex, columnCount)
outRect.right = getEndOffsetWithEdge(spacing, columnIndex, columnCount)
outRect.top = getStartOffsetWithEdge(spacing, rowIndex, rowCount)
outRect.bottom = getEndOffsetWithEdge(spacing, rowIndex, rowCount)
}
RecyclerView.HORIZONTAL -> {
outRect.top = getStartOffsetWithEdge(spacing, columnIndex, columnCount)
outRect.bottom = getEndOffsetWithEdge(spacing, columnIndex, columnCount)
outRect.left = getStartOffsetWithEdge(spacing, rowIndex, rowCount)
outRect.right = getEndOffsetWithEdge(spacing, rowIndex, rowCount)
}
}
} else {
when (orientation) {
RecyclerView.VERTICAL -> {
outRect.left = getStartOffsetWithoutEdge(spacing, columnIndex, columnCount)
outRect.right = getEndOffsetWithoutEdge(spacing, columnIndex, columnCount)
outRect.top = getStartOffsetWithoutEdge(spacing, rowIndex, rowCount)
outRect.bottom = getEndOffsetWithoutEdge(spacing, rowIndex, rowCount)
}
RecyclerView.HORIZONTAL -> {
outRect.top = getStartOffsetWithoutEdge(spacing, columnIndex, columnCount)
outRect.bottom = getEndOffsetWithoutEdge(spacing, columnIndex, columnCount)
outRect.left = getStartOffsetWithoutEdge(spacing, rowIndex, rowCount)
outRect.right = getEndOffsetWithoutEdge(spacing, rowIndex, rowCount)
}
}
}
} else {
outRect.left = 0
outRect.right = 0
outRect.top = 0
outRect.bottom = 0
}
}
private fun getColumnCount(parent: RecyclerView) = when (val layoutManager = parent.layoutManager) {
is GridLayoutManager -> layoutManager.spanCount
is StaggeredGridLayoutManager -> layoutManager.spanCount
else -> 1
}
private fun getRowCount(parent: RecyclerView, columnCount: Int) =
parent.adapter?.itemCount?.div(columnCount)?.minus(headerRowCount)
private fun getOrientation(parent: RecyclerView) = when (val layoutManager = parent.layoutManager) {
is LinearLayoutManager -> layoutManager.orientation
is GridLayoutManager -> layoutManager.orientation
is StaggeredGridLayoutManager -> layoutManager.orientation
else -> RecyclerView.VERTICAL
}
private fun getStartOffsetWithEdge(spacing: Int, columnIndex: Int, columnCount: Int?): Int {
if (columnCount == null) return spacing
return spacing - spacing * columnIndex / columnCount
}
private fun getEndOffsetWithEdge(spacing: Int, columnIndex: Int, columnCount: Int?): Int {
if (columnCount == null) return 0
return spacing * (columnIndex + 1) / columnCount
}
private fun getStartOffsetWithoutEdge(spacing: Int, columnIndex: Int, columnCount: Int?): Int {
if (columnCount == null) return 0
return spacing * columnIndex / columnCount
}
private fun getEndOffsetWithoutEdge(spacing: Int, columnIndex: Int, columnCount: Int?): Int {
if (columnCount == null) return spacing
return spacing - spacing * (columnIndex + 1) / columnCount
}
}