Skip to content

Instantly share code, notes, and snippets.

@pythoncat1024
Last active October 20, 2019 12:39
Show Gist options
  • Save pythoncat1024/7b9b3df5458a1671e674f437d40b7bd2 to your computer and use it in GitHub Desktop.
Save pythoncat1024/7b9b3df5458a1671e674f437d40b7bd2 to your computer and use it in GitHub Desktop.
recyclerView grid 模式的分割线绘制
private class StaggeredGridItemDecoration(
context: Context,
orientation: Int,
private val spanCount: Int
) : RecyclerView.ItemDecoration() {
companion object {
const val HORIZONTAL = LinearLayout.HORIZONTAL
const val VERTICAL = LinearLayout.VERTICAL
const val STAGGEREDGRID = 31
private val TAG = "DividerItem"
private val ATTRS = intArrayOf(android.R.attr.listDivider)
}
private var mDivider: Drawable? = null
/**
* Current orientation. Either [.HORIZONTAL] or [.VERTICAL].
*/
private var mOrientation: Int = 0
private val mBounds = Rect()
init {
val a = context.obtainStyledAttributes(ATTRS)
mDivider = a.getDrawable(0)
if (mDivider == null) {
Log.w(
TAG,
"@android:attr/listDivider was not set in the theme used for this "
+ "DividerItemDecoration. Please set that attribute all call setDrawable()"
)
}
a.recycle()
setOrientation(orientation)
}
/**
* Sets the orientation for this divider. This should be called if
* [RecyclerView.LayoutManager] changes orientation.
*
* @param orientation [.HORIZONTAL] or [.VERTICAL]
*/
fun setOrientation(orientation: Int) {
require(
!(orientation != HORIZONTAL
&& orientation != VERTICAL
&& orientation != STAGGEREDGRID)
) { "Invalid orientation. It should be either HORIZONTAL or VERTICAL" }
mOrientation = orientation
}
/**
* Sets the [Drawable] for this divider.
*
* @param drawable Drawable that should be used as a divider.
*/
fun setDrawable(drawable: Drawable) {
mDivider = drawable
}
/**
* @return the [Drawable] for this divider.
*/
fun getDrawable(): Drawable? {
return mDivider
}
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
if (parent.layoutManager == null || mDivider == null) {
return
}
when (mOrientation) {
VERTICAL -> {
drawVertical(c, parent)
}
HORIZONTAL -> {
drawHorizontal(c, parent)
}
STAGGEREDGRID -> {
drawMulti(c, parent)
}
}
}
private fun drawMulti(canvas: Canvas, parent: RecyclerView) {
drawVertical(canvas, parent)
drawHorizontal(canvas, parent)
}
private fun drawVertical(canvas: Canvas, parent: RecyclerView) {
canvas.save()
var left: Int
val right: Int
var itemRight = 0
if (parent.clipToPadding) {
left = parent.paddingLeft
right = parent.width - parent.paddingRight
canvas.clipRect(
left, parent.paddingTop, right,
parent.height - parent.paddingBottom
)
} else {
@Suppress("UNUSED_VALUE")
left = 0
right = parent.width
}
val childCount = parent.childCount
LogUtils.e("child count = $childCount")
for (i in 0 until childCount) {
var count = ((i + 1) % spanCount)
count = if (count == 0) spanCount else count
// LogUtils.w("$i , $count")
itemRight = count * right / spanCount
left = (count - 1) * right / spanCount
val child = parent.getChildAt(i)
parent.getDecoratedBoundsWithMargins(child, mBounds)
val bottom = mBounds.bottom + child.translationY.roundToInt()
val top = bottom - mDivider!!.intrinsicHeight
mDivider!!.setBounds(left, top, itemRight, bottom)
mDivider!!.draw(canvas)
}
canvas.restore()
}
private fun drawHorizontal(canvas: Canvas, parent: RecyclerView) {
canvas.save()
var top: Int
val bottom: Int
var itemHeight = 0
if (parent.clipToPadding) {
top = parent.paddingTop
bottom = parent.height - parent.paddingBottom
canvas.clipRect(
parent.paddingLeft, top,
parent.width - parent.paddingRight, bottom
)
} else {
top = 0
bottom = parent.height
}
val childCount = parent.childCount
LogUtils.e("child count = $childCount")
var line = 0
val totalLine = childCount / spanCount + if (childCount % spanCount > 0) 1 else 0
for (i in 0 until childCount) {
if ((i + 1) % (spanCount) == 1) {
line += 1
}
itemHeight = bottom * line / totalLine
top = bottom * (line - 1) / totalLine
LogUtils.w("$i , $line , $itemHeight")
val child = parent.getChildAt(i)
parent.layoutManager!!.getDecoratedBoundsWithMargins(child, mBounds)
val right = mBounds.right + child.translationX.roundToInt()
val left = right - mDivider!!.intrinsicWidth
mDivider!!.setBounds(left, top, right, itemHeight)
mDivider!!.draw(canvas)
}
canvas.restore()
}
override fun getItemOffsets(
outRect: Rect, view: View, parent: RecyclerView,
state: RecyclerView.State
) {
if (mDivider == null) {
outRect.set(0, 0, 0, 0)
return
}
when (mOrientation) {
VERTICAL -> {
outRect.set(0, 0, 0, mDivider!!.intrinsicHeight)
}
HORIZONTAL -> {
outRect.set(0, 0, mDivider!!.intrinsicWidth, 0)
}
STAGGEREDGRID -> {
outRect.set(0, 0, mDivider!!.intrinsicWidth, mDivider!!.intrinsicHeight)
}
}
}
}
@pythoncat1024
Copy link
Author

调用也很简单,就是要加一个 spanCount:Int 参数。

recyclerView.addItemDecoration(
            StaggeredGridItemDecoration(
                this,
                StaggeredGridItemDecoration.STAGGEREDGRID,
                4
            )
        )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment