I have to add internal colored grid to my RecyclerView with GridLayoutManager.
Adding space to ViewHolders is not my solution because I have rounded background in recyclerView and background in viewHolders breaks them.
Standart DividerItemDecoration gives me exactly what I need, except I can choose ONLY horizontal or vertical lines and not both.
I've found answers which gave me internal grid by spacing via getItemOffsets()
, but I can't color fill outRect.
What is the best way to achieve this idea?
So I've achieved this task by simplifying standart androidx.recyclerview.widget.DividerItemDecoration
by deleting all separation by HORIZONTAL and VERTICAL in code. As the result I have internal horizontal+vertical lines.
Applying decoration:
myRecyclerView.addItemDecoration(GridDividerItemDecoration(requireContext()))
The whole decoration class:
class GridDividerItemDecoration(context: Context) : ItemDecoration() {
private val mBounds = Rect()
private var mDivider: Drawable?
fun setDrawable(drawable: Drawable) {
mDivider = drawable
}
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
if (parent.layoutManager == null || mDivider == null) {
return
}
drawVertical(c, parent)
drawHorizontal(c, parent)
}
private fun drawVertical(canvas: Canvas, parent: RecyclerView) {
canvas.save()
val left: Int
val right: Int
if (parent.clipToPadding) {
left = parent.paddingLeft
right = parent.width - parent.paddingRight
canvas.clipRect(left, parent.paddingTop, right,
parent.height - parent.paddingBottom)
} else {
left = 0
right = parent.width
}
val childCount = parent.childCount
for (i in 0 until childCount) {
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, right, bottom)
mDivider!!.draw(canvas)
}
canvas.restore()
}
private fun drawHorizontal(canvas: Canvas, parent: RecyclerView) {
canvas.save()
val top: Int
val bottom: Int
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
for (i in 0 until childCount) {
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, bottom)
mDivider!!.draw(canvas)
}
canvas.restore()
}
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView,
state: RecyclerView.State) {
if (mDivider == null) {
outRect[0, 0, 0] = 0
return
}
outRect[0, 0, 0] = mDivider!!.intrinsicHeight
outRect[0, 0, mDivider!!.intrinsicWidth] = 0
}
companion object {
private const val TAG = "DividerItem"
private val ATTRS = intArrayOf(R.attr.listDivider)
}
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()
}
}