Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
基于公式法写的一个 GridSpaceItemDecoration, 实现 GridLayoutManager 居中元素空隙
import android.graphics.Rect
import android.view.View
import androidx.annotation.Dimension
import androidx.core.text.TextUtilsCompat
import androidx.core.view.ViewCompat
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import li.wafer.nbnhhshandroid.common.extensions.dipToPx
import java.util.*
import kotlin.math.roundToInt
class GridSpaceItemDecoration(
@Dimension(unit = Dimension.DP) private val start: Double = 0.0,
@Dimension(unit = Dimension.DP) private val top: Double = 0.0,
@Dimension(unit = Dimension.DP) private val end: Double = 0.0,
@Dimension(unit = Dimension.DP) private val bottom: Double = 0.0,
@Dimension(unit = Dimension.DP) private val horizontal: Double = 0.0,
@Dimension(unit = Dimension.DP) private val vertical: Double = 0.0
) : RecyclerView.ItemDecoration() {
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
super.getItemOffsets(outRect, view, parent, state)
val gridLayoutManager = parent.layoutManager as? GridLayoutManager ?: return
val itemCount = parent.adapter?.itemCount ?: return
val spanCount = gridLayoutManager.spanCount
val position = parent.getChildLayoutPosition(view)
val spanSizeLookup = gridLayoutManager.spanSizeLookup
val spanSize = spanSizeLookup.getSpanSize(position)
val spanIndex = spanSizeLookup.getSpanIndex(position, spanCount)
val spanGroupIndex =
spanSizeLookup.getSpanGroupIndex(position, spanCount) // nMinusOne in vertical
val isRtl =
TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault()) == ViewCompat.LAYOUT_DIRECTION_RTL
val verticalSpanCount = spanSizeLookup.getSpanGroupIndex(itemCount - 1, spanCount) + 1
val verticalSizeAvg =
(top + bottom + vertical * (verticalSpanCount - 1)) / verticalSpanCount
val horizontalSizeAvg =
(start + end + horizontal * (spanCount - 1)) / spanCount
val start = calculateStartOffsets(spanIndex, horizontalSizeAvg)
val end =
calculateEndOffset((spanCount - 1) - (spanIndex + spanSize - 1), horizontalSizeAvg)
val top = calculateTopOffsets(spanGroupIndex, verticalSizeAvg)
val bottom =
calculateBottomOffsets((verticalSpanCount - 1) - (spanGroupIndex), verticalSizeAvg)
val (left, right) = if (isRtl) {
end to start
} else {
start to end
}
val context = parent.context
outRect.set(
context.dipToPx(left),
context.dipToPx(top),
context.dipToPx(right),
context.dipToPx(bottom)
)
}
@Dimension(unit = Dimension.DP)
private fun calculateBottomOffsets(
nMinusOne: Int,
@Dimension(unit = Dimension.DP) verticalSizeAvg: Double
): Int {
return calculateOffset(bottom, nMinusOne, vertical - verticalSizeAvg)
}
@Dimension(unit = Dimension.DP)
private fun calculateTopOffsets(
nMinusOne: Int,
@Dimension(unit = Dimension.DP) verticalSizeAvg: Double
): Int {
return calculateOffset(top, nMinusOne, vertical - verticalSizeAvg)
}
@Dimension(unit = Dimension.DP)
private fun calculateStartOffsets(
nMinusOne: Int,
@Dimension(unit = Dimension.DP) horizontalSizeAvg: Double
): Int {
return calculateOffset(start, nMinusOne, horizontal - horizontalSizeAvg)
}
private fun calculateOffset(
initialValue: Double,
nMinusOne: Int,
commonDifference: Double
): Int {
return (initialValue + nMinusOne * commonDifference).roundToInt()
}
private fun calculateEndOffset(nMinusOne: Int, horizontalSizeAvg: Double): Int {
return calculateOffset(
end,
(nMinusOne),
horizontal - horizontalSizeAvg
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.