Skip to content

Instantly share code, notes, and snippets.

@hector6872
Last active March 22, 2019 09:54
Show Gist options
  • Select an option

  • Save hector6872/c03e61b149e81480a8036bcecd3f8e0f to your computer and use it in GitHub Desktop.

Select an option

Save hector6872/c03e61b149e81480a8036bcecd3f8e0f to your computer and use it in GitHub Desktop.
StickySectionItemDecoration Kotlin
class StickySectionItemDecoration(
private val recyclerView: RecyclerView,
private val callback: Callback
) : RecyclerView.ItemDecoration() {
private var headerViewCache: View? = null
private var isInLayout = false
interface Callback {
fun isHeader(position: Int): Boolean
fun getHeaderView(): View?
fun onHeaderViewClick()
}
init {
recyclerView.addOnItemTouchListener(object : OnItemTouchListener {
override fun onTouchEvent(
rv: RecyclerView,
e: MotionEvent
) {
}
override fun onInterceptTouchEvent(
rv: RecyclerView,
e: MotionEvent
): Boolean {
if (!isInLayout && isNotNull(headerViewCache) && e.y < headerViewCache!!.height) {
if (e.action == MotionEvent.ACTION_UP) callback.onHeaderViewClick()
return true
}
return false
}
override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {}
})
}
override fun onDrawOver(
c: Canvas,
parent: RecyclerView,
state: RecyclerView.State
) {
if (isNull(headerViewCache) || headerViewCache != callback.getHeaderView()) {
headerViewCache = callback.getHeaderView()
headerViewCache?.let {
calculateLayoutSize(it, parent)
}
}
for (i in 0 until parent.childCount) {
val child = parent.getChildAt(i)
val position = parent.getChildAdapterPosition(child)
if (callback.isHeader(position)) {
val firstCompletelyVisiblePosition = (parent.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition()
isInLayout = firstCompletelyVisiblePosition <= position
break
}
}
if (!isInLayout and isNotNull(headerViewCache)) {
drawHeader(c, headerViewCache!!)
} else {
super.onDrawOver(c, parent, state)
}
}
private fun drawHeader(
c: Canvas,
headerView: View
) {
c.save()
c.translate(recyclerView.paddingLeft.toFloat(), if (recyclerView.clipToPadding) recyclerView.paddingTop.toFloat() else 0f)
headerView.draw(c)
c.restore()
}
private fun calculateLayoutSize(
view: View,
parent: ViewGroup
) {
val widthSpec = View.MeasureSpec.makeMeasureSpec(parent.width, View.MeasureSpec.EXACTLY)
val heightSpec = View.MeasureSpec.makeMeasureSpec(parent.height, View.MeasureSpec.UNSPECIFIED)
val childWidth = ViewGroup.getChildMeasureSpec(widthSpec, parent.paddingStart + parent.paddingEnd, view.layoutParams.width)
val childHeight = ViewGroup.getChildMeasureSpec(heightSpec, parent.paddingTop + parent.paddingBottom, view.layoutParams.height)
view.apply {
measure(childWidth, childHeight)
layout(0, 0, view.measuredWidth, view.measuredHeight)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment