-
Android Sticky Header RecyclerViewAndroid 2021. 6. 17. 21:46반응형
https://github.com/DNights/StickyHeaderRecyclerViewSample
RecyclerView 에서 Sticky Header 를 구현 샘플 코드입니다.
ItemDecoration 을 사용하여 상단의 Top holder를 RecyclerView 위에 그려서 고정된것처럼 보이게 하는 방법입니다.
아래의 코드는 StickyHeaderItemDecoration 의 전체 코드입니다.
[StickyHeaderItemDecoration]
package dev.dnights.stickyheaderrecyclerviewsample import android.graphics.Canvas import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView class StickyHeaderItemDecoration(private val sectionCallback: SectionCallback) : RecyclerView.ItemDecoration() { override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { super.onDrawOver(c, parent, state) val topChild = parent.getChildAt(0) ?: return val topChildPosition = parent.getChildAdapterPosition(topChild) if (topChildPosition == RecyclerView.NO_POSITION) { return } val currentHeader: View = sectionCallback.getHeaderLayoutView(parent, topChildPosition) ?: return fixLayoutSize(parent, currentHeader, topChild.measuredHeight) val contactPoint = currentHeader.bottom val childInContact: View = (getChildInContact(parent, contactPoint) ?: return) val childAdapterPosition = parent.getChildAdapterPosition(childInContact) if (childAdapterPosition == -1) { return } if (sectionCallback.isHeader(childAdapterPosition)) { moveHeader(c, currentHeader, childInContact) return } drawHeader(c, currentHeader) } private fun getChildInContact(parent: RecyclerView, contactPoint: Int): View? { var childInContact: View? = null for (i in 0 until parent.childCount) { val child = parent.getChildAt(i) if (child.bottom > contactPoint) { if (child.top <= contactPoint) { childInContact = child break } } } return childInContact } private fun moveHeader(c: Canvas, currentHeader: View, nextHeader: View) { c.save() c.translate(0f, nextHeader.top - currentHeader.height.toFloat()) currentHeader.draw(c) c.restore() } private fun drawHeader(c: Canvas, header: View) { c.save() c.translate(0f, 0f) header.draw(c) c.restore() } private fun fixLayoutSize(parent: ViewGroup, view: View, height: Int) { val widthSpec = View.MeasureSpec.makeMeasureSpec(parent.width, View.MeasureSpec.EXACTLY) val heightSpec = View.MeasureSpec.makeMeasureSpec(parent.height, View.MeasureSpec.EXACTLY) val childWidth: Int = ViewGroup.getChildMeasureSpec( widthSpec, parent.paddingLeft + parent.paddingRight, view.layoutParams.width ) val childHeight: Int = ViewGroup.getChildMeasureSpec( heightSpec, parent.paddingTop + parent.paddingBottom, height ) view.measure(childWidth, childHeight) view.layout(0, 0, view.measuredWidth, view.measuredHeight) } interface SectionCallback { fun isHeader(position: Int): Boolean fun getHeaderLayoutView(list: RecyclerView, position: Int): View? } }
onDrawOver 에서 RecycleView 위에 덮어서 화면을 그리며
callback 을 통해서 현재 상단 위치의 item의 view type이 header 인지 여부와 header의 view 를 받아서
cavers에 moveHeader를 통해서 header가 만났을때 이동하는 모습을 그리거나
drawHeader을 통해서 항상 상단에 표기되도록 그립니다.
[참고 링크]
https://leveloper.tistory.com/198
https://dailylonnie0125.tistory.com/22
반응형'Android' 카테고리의 다른 글
Android adb 사용 여부 앱에서 확인하는 법 (0) 2021.12.14 Android 12 Splash Screen (스플래시 스크린) (0) 2021.12.09 Android studio Gradle 7.0 upgrade (0) 2021.07.04 Jetpack Compose Setting (0) 2021.06.30 Android Studio 자동완성 기능 안될경우 (with. MAC) (3) 2021.04.29 Android Notifications(알림) 표시 (0) 2021.03.14 [안드로이드] Intent로 이미지 가져오기 (0) 2021.03.06 Android TextView URL link 처리하기 (0) 2020.12.28