Last active
April 22, 2021 11:22
-
-
Save code-n-roll/6740fcaf9155c41f6ab71668211f4842 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
import android.graphics.Canvas | |
import android.graphics.Rect | |
import android.graphics.drawable.Drawable | |
import android.view.View | |
import android.widget.LinearLayout | |
import androidx.annotation.DrawableRes | |
import androidx.core.content.ContextCompat | |
import androidx.core.content.res.use | |
import androidx.recyclerview.widget.GridLayoutManager | |
import androidx.recyclerview.widget.LinearLayoutManager | |
import androidx.recyclerview.widget.RecyclerView | |
import app.zenia.ZeniaApplication | |
class InnerOuterItemDecoration( | |
private val innerMarginInPx: Int = 0, | |
private val outerHorizontalMarginInPx: Int = 0, | |
private val outerVerticalMarginInPx: Int = 0, | |
@DrawableRes private val dividerDrawableId: Int? = null, | |
private val dividerPaddingLeftInPx: Int = 0, | |
private val dividerPaddingRightInPx: Int = 0, | |
hasDivider: Boolean = false, | |
private val dividerOrientation: Int = VERTICAL | |
) : RecyclerView.ItemDecoration() { | |
companion object { | |
private val ATTRS = intArrayOf(android.R.attr.listDivider) | |
private const val HORIZONTAL = LinearLayout.HORIZONTAL | |
private const val VERTICAL = LinearLayout.VERTICAL | |
} | |
private var divider: Drawable? = null | |
private val bounds = Rect() | |
init { | |
if (hasDivider) { | |
if (dividerDrawableId == null) { | |
ZeniaApplication.context.theme.obtainStyledAttributes(ATTRS).use { | |
divider = it.getDrawable(0) | |
} | |
} else { | |
divider = ContextCompat.getDrawable(ZeniaApplication.context, dividerDrawableId) | |
} | |
} | |
} | |
override fun onDrawOver(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) { | |
val divider = this.divider ?: return | |
if (parent.layoutManager == null) { | |
return | |
} | |
if (dividerOrientation == VERTICAL) { | |
drawVertical(canvas, parent, divider) | |
} else { | |
drawHorizontal(canvas, parent, divider) | |
} | |
} | |
override fun getItemOffsets( | |
outRect: Rect, | |
view: View, | |
parent: RecyclerView, | |
state: RecyclerView.State | |
) { | |
val currentItem = parent.getChildAdapterPosition(view) | |
val itemCount = parent.adapter?.itemCount ?: 0 | |
when (val layoutManager = parent.layoutManager) { | |
// order is matter, because GridLayoutManager is inherited from LinearLayoutManager | |
is GridLayoutManager -> { | |
val spanCount = layoutManager.spanCount | |
if (layoutManager.orientation == GridLayoutManager.HORIZONTAL) { | |
when (currentItem) { | |
in 0 until spanCount -> { | |
outRect.left = outerHorizontalMarginInPx | |
} | |
in itemCount - spanCount until itemCount -> { | |
outRect.left = innerMarginInPx | |
outRect.right = outerHorizontalMarginInPx | |
} | |
else -> { | |
outRect.left = innerMarginInPx | |
} | |
} | |
outRect.top = outerVerticalMarginInPx | |
outRect.bottom = outerVerticalMarginInPx | |
} | |
} | |
is LinearLayoutManager -> { | |
if (layoutManager.orientation == LinearLayoutManager.VERTICAL) { | |
if (currentItem != 0) { | |
outRect.top = innerMarginInPx | |
} | |
outRect.left = outerHorizontalMarginInPx | |
outRect.right = outerHorizontalMarginInPx | |
if (currentItem == 0) { | |
outRect.top = outerVerticalMarginInPx | |
} | |
if (currentItem == itemCount - 1) { | |
outRect.bottom = outerVerticalMarginInPx | |
} | |
} else { | |
when (currentItem) { | |
0 -> { | |
outRect.left = outerHorizontalMarginInPx | |
} | |
itemCount - 1 -> { | |
outRect.left = innerMarginInPx | |
outRect.right = outerHorizontalMarginInPx | |
} | |
else -> { | |
outRect.left = innerMarginInPx | |
} | |
} | |
outRect.top = outerVerticalMarginInPx | |
outRect.bottom = outerVerticalMarginInPx | |
} | |
} | |
} | |
} | |
private fun drawVertical(canvas: Canvas, parent: RecyclerView, divider: Drawable) { | |
canvas.save() | |
val left: Int | |
val right: Int | |
if (parent.clipToPadding) { | |
left = parent.paddingLeft + dividerPaddingLeftInPx | |
right = parent.width - parent.paddingRight - dividerPaddingRightInPx | |
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, bounds) | |
val bottom: Int = bounds.bottom + Math.round(child.translationY) | |
val top: Int = bottom - divider.intrinsicHeight | |
divider.setBounds(left, top, right, bottom) | |
divider.draw(canvas) | |
} | |
canvas.restore() | |
} | |
private fun drawHorizontal(canvas: Canvas, parent: RecyclerView, divider: Drawable) { | |
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, bounds) | |
val right: Int = bounds.right + Math.round(child.translationX) | |
val left: Int = right - divider.intrinsicWidth | |
divider.setBounds(left, top, right, bottom) | |
divider.draw(canvas) | |
} | |
canvas.restore() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment