Skip to content

Instantly share code, notes, and snippets.

@marius-m
Created April 21, 2022 10:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marius-m/c8e39761bf054d645b548cd4f63a13c4 to your computer and use it in GitHub Desktop.
Save marius-m/c8e39761bf054d645b548cd4f63a13c4 to your computer and use it in GitHub Desktop.
/**
* Inspiration and main resource taken from [com.google.android.material.divider.MaterialDividerItemDecoration]
*
* Divider is solving only vertical scrolling use case.
* It divides items that are vertically scrolled + "divides" the first item (paints divider on top)
*
* Will not paint a full rectangle if the [RecyclerView] scrolls only in one direction, because
* the dividers are pointed on top. So the dividers "stays on top" whenever scrolling.
*/
class MaterialDividerVerticalOnlyWithFirstItem(
private val context: Context,
private val gridSpanSize: Int = 1,
) : RecyclerView.ItemDecoration() {
private var dividerDrawable: Drawable
private var thickness = 0
private var insetStart = 0
private var insetEnd = 0
private val tempRect = Rect()
@ColorInt private var color = 0
init {
this.color = ContextCompat.getColor(context, R.color.cardStroke)
this.thickness = context.dpToPx(1)
this.insetStart = context.dpToPx(12)
this.insetEnd = context.dpToPx(12)
dividerDrawable = ShapeDrawable()
setDividerColor(color)
}
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
if (parent.layoutManager == null) {
return
}
drawOnFirstItemForVertical(c, parent)
drawForVerticalOrientation(c, parent)
}
private fun drawOnFirstItemForVertical(canvas: Canvas, parent: RecyclerView) {
canvas.save()
var left: Int
var 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 isRtl = ViewCompat.getLayoutDirection(parent) == ViewCompat.LAYOUT_DIRECTION_RTL
left += if (isRtl) insetEnd else insetStart
right -= if (isRtl) insetStart else insetEnd
val childCount = parent.childCount
if (childCount > 0) {
val child = parent.getChildAt(0)
parent.getDecoratedBoundsWithMargins(child, tempRect)
// Take into consideration any translationY added to the view.
val bottom: Int = tempRect.top - Math.round(child.translationY)
val top: Int = bottom + thickness
dividerDrawable.setBounds(left, top, right, bottom)
dividerDrawable.draw(canvas)
}
canvas.restore()
}
private fun drawForVerticalOrientation(canvas: Canvas, parent: RecyclerView) {
canvas.save()
var left: Int
var 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 isRtl = ViewCompat.getLayoutDirection(parent) == ViewCompat.LAYOUT_DIRECTION_RTL
left += if (isRtl) insetEnd else insetStart
right -= if (isRtl) insetStart else insetEnd
val childCount = parent.childCount
for (i in 0 until childCount) {
val child = parent.getChildAt(i)
parent.getDecoratedBoundsWithMargins(child, tempRect)
// Take into consideration any translationY added to the view.
val bottom: Int = tempRect.bottom + Math.round(child.translationY)
val top: Int = bottom - dividerDrawable.intrinsicHeight - thickness
dividerDrawable.setBounds(left, top, right, bottom)
dividerDrawable.draw(canvas)
}
canvas.restore()
}
/**
* Draws a divider for the horizontal orientation of the recycler view. The divider itself will be
* vertical.
*/
fun setDividerColor(@ColorInt color: Int) {
this.color = color
dividerDrawable = DrawableCompat.wrap(dividerDrawable)
DrawableCompat.setTint(dividerDrawable, color)
}
override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
val pos = parent.getChildAdapterPosition(view)
if (pos < gridSpanSize) {
outRect[0, 0, 0] = 0
outRect.top = thickness
outRect.bottom = dividerDrawable.intrinsicHeight + thickness
} else {
outRect[0, 0, 0] = 0
outRect.bottom = dividerDrawable.intrinsicHeight + thickness
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment