Last active
March 22, 2019 09:54
-
-
Save hector6872/c03e61b149e81480a8036bcecd3f8e0f to your computer and use it in GitHub Desktop.
StickySectionItemDecoration Kotlin
This file contains hidden or 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
| 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