Created
April 21, 2022 10:18
-
-
Save marius-m/c8e39761bf054d645b548cd4f63a13c4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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