Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Item Decorator for sticky headers in Kotlin
package com.filipkowicz.headeritemdecorator
/*
solution based on - based on Sevastyan answer on StackOverflow
changes:
- take to account views offsets
- transformed to Kotlin
- now works on viewHolders
- try to cache viewHolders between draw's
- support for clipToPadding=false
Source:
https://stackoverflow.com/questions/32949971/how-can-i-make-sticky-headers-in-recyclerview-without-external-lib/44327350#44327350
*/
import android.graphics.*
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
class HeaderItemDecoration(
parent: RecyclerView,
private val shouldFadeOutHeader: Boolean = false,
private val isHeader: (itemPosition: Int) -> Boolean
) : RecyclerView.ItemDecoration() {
private var currentHeader: Pair<Int, RecyclerView.ViewHolder>? = null
init {
parent.adapter?.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
override fun onChanged() {
// clear saved header as it can be outdated now
currentHeader = null
}
})
parent.doOnEachNextLayout {
// clear saved layout as it may need layout update
currentHeader = null
}
// handle click on sticky header
parent.addOnItemTouchListener(object : RecyclerView.SimpleOnItemTouchListener() {
override fun onInterceptTouchEvent(
recyclerView: RecyclerView,
motionEvent: MotionEvent
): Boolean {
return if (motionEvent.action == MotionEvent.ACTION_DOWN) {
motionEvent.y <= currentHeader?.second?.itemView?.bottom ?: 0
} else false
}
})
}
override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
super.onDrawOver(c, parent, state)
//val topChild = parent.getChildAt(0) ?: return
val topChild = parent.findChildViewUnder(
parent.paddingLeft.toFloat(),
parent.paddingTop.toFloat() /*+ (currentHeader?.second?.itemView?.height ?: 0 )*/
) ?: return
val topChildPosition = parent.getChildAdapterPosition(topChild)
if (topChildPosition == RecyclerView.NO_POSITION) {
return
}
val headerView = getHeaderViewForItem(topChildPosition, parent) ?: return
val contactPoint = headerView.bottom + parent.paddingTop
val childInContact = getChildInContact(parent, contactPoint) ?: return
if (isHeader(parent.getChildAdapterPosition(childInContact))) {
moveHeader(c, headerView, childInContact, parent.paddingTop)
return
}
drawHeader(c, headerView, parent.paddingTop)
}
private fun getHeaderViewForItem(itemPosition: Int, parent: RecyclerView): View? {
if (parent.adapter == null) {
return null
}
val headerPosition = getHeaderPositionForItem(itemPosition)
if (headerPosition == RecyclerView.NO_POSITION) return null
val headerType = parent.adapter?.getItemViewType(headerPosition) ?: return null
// if match reuse viewHolder
if (currentHeader?.first == headerPosition && currentHeader?.second?.itemViewType == headerType) {
return currentHeader?.second?.itemView
}
val headerHolder = parent.adapter?.createViewHolder(parent, headerType)
if (headerHolder != null) {
parent.adapter?.onBindViewHolder(headerHolder, headerPosition)
fixLayoutSize(parent, headerHolder.itemView)
// save for next draw
currentHeader = headerPosition to headerHolder
}
return headerHolder?.itemView
}
private fun drawHeader(c: Canvas, header: View, paddingTop: Int) {
c.save()
c.translate(0f, paddingTop.toFloat())
header.draw(c)
c.restore()
}
private fun moveHeader(c: Canvas, currentHeader: View, nextHeader: View, paddingTop: Int) {
c.save()
if (!shouldFadeOutHeader) {
c.clipRect(0, paddingTop, c.width, paddingTop + currentHeader.height)
} else {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
c.saveLayerAlpha(
RectF(0f, 0f, c.width.toFloat(), c.height.toFloat()),
(((nextHeader.top - paddingTop) / nextHeader.height.toFloat()) * 255).toInt()
)
} else {
c.saveLayerAlpha(
0f, 0f, c.width.toFloat(), c.height.toFloat(),
(((nextHeader.top - paddingTop) / nextHeader.height.toFloat()) * 255).toInt(),
Canvas.ALL_SAVE_FLAG
)
}
}
c.translate(0f, (nextHeader.top - currentHeader.height).toFloat() /*+ paddingTop*/)
currentHeader.draw(c)
if (shouldFadeOutHeader) {
c.restore()
}
c.restore()
}
private fun getChildInContact(parent: RecyclerView, contactPoint: Int): View? {
var childInContact: View? = null
for (i in 0 until parent.childCount) {
val child = parent.getChildAt(i)
val mBounds = Rect()
parent.getDecoratedBoundsWithMargins(child, mBounds)
if (mBounds.bottom > contactPoint) {
if (mBounds.top <= contactPoint) {
// This child overlaps the contactPoint
childInContact = child
break
}
}
}
return childInContact
}
/**
* Properly measures and layouts the top sticky header.
*
* @param parent ViewGroup: RecyclerView in this case.
*/
private fun fixLayoutSize(parent: ViewGroup, view: View) {
// Specs for parent (RecyclerView)
val widthSpec = View.MeasureSpec.makeMeasureSpec(parent.width, View.MeasureSpec.EXACTLY)
val heightSpec =
View.MeasureSpec.makeMeasureSpec(parent.height, View.MeasureSpec.UNSPECIFIED)
// Specs for children (headers)
val childWidthSpec = ViewGroup.getChildMeasureSpec(
widthSpec,
parent.paddingLeft + parent.paddingRight,
view.layoutParams.width
)
val childHeightSpec = ViewGroup.getChildMeasureSpec(
heightSpec,
parent.paddingTop + parent.paddingBottom,
view.layoutParams.height
)
view.measure(childWidthSpec, childHeightSpec)
view.layout(0, 0, view.measuredWidth, view.measuredHeight)
}
private fun getHeaderPositionForItem(itemPosition: Int): Int {
var headerPosition = RecyclerView.NO_POSITION
var currentPosition = itemPosition
do {
if (isHeader(currentPosition)) {
headerPosition = currentPosition
break
}
currentPosition -= 1
} while (currentPosition >= 0)
return headerPosition
}
}
inline fun View.doOnEachNextLayout(crossinline action: (view: View) -> Unit) {
addOnLayoutChangeListener { view, _, _, _, _, _, _, _, _ ->
action(
view
)
}
}
@leodeleon22

This comment has been minimized.

Copy link

@leodeleon22 leodeleon22 commented Apr 16, 2019

Works like a charm ✌️

@codefury

This comment has been minimized.

Copy link

@codefury codefury commented May 18, 2019

Please show adapter implementation for this and how to addItemDecoration?

@filipkowicz

This comment has been minimized.

Copy link
Owner Author

@filipkowicz filipkowicz commented Jul 2, 2019

@codefury my adapter implementation will not be usefull as I usually use autogenerated dagger adapters but normal regular adapter which will show headers correctly without being sticky should works here as well

addItemDecoration in Kotlin :

recyclerList.addItemDecoration(HeaderItemDecoration(recyclerList) { itemPosition ->
                    if (itemPosition >= 0 && itemPosition < adapter.itemCount) {
                        // your code to check if item at itemPosition is header
                    } else false
                })
@dkarataiev

This comment has been minimized.

Copy link

@dkarataiev dkarataiev commented Jul 2, 2019

Please show adapter implementation for this and how to addItemDecoration?

Something like that:

recyclerView.addItemDecoration(HeaderItemDecoration(recyclerView, isHeader()))
    private fun isHeader(): (itemPosition: Int) -> Boolean {
        return {
            (recyclerView.adapter as yourAdapter).data[it].type == HEADER
        }
    }

And a standard adapter with overwritten: onBindViewHolder, getItemViewType and onCreateViewHolder.

@vburovsoftermii

This comment has been minimized.

Copy link

@vburovsoftermii vburovsoftermii commented Jul 10, 2019

I can't figured out how I can to set bottom padding to header view.

@filipkowicz

This comment has been minimized.

Copy link
Owner Author

@filipkowicz filipkowicz commented Jul 12, 2019

@vburovsoftermii could you provide some design, can't understand where you want to have padding in header (as far as header is placed on Top of recycler)

@Timoteohss

This comment has been minimized.

Copy link

@Timoteohss Timoteohss commented Sep 30, 2019

Works perfectly, but why are my headers half-transparent?

@frakc

This comment has been minimized.

Copy link

@frakc frakc commented Oct 1, 2019

@Timoteohss

Works perfectly, but why are my headers half-transparent?

did you set background for your header view? ;)

@xBlackCat

This comment has been minimized.

Copy link

@xBlackCat xBlackCat commented Oct 10, 2019

Is there exist some way to handle stick header events in usual way? I mean stick header don't handle onClick events of its children or itself.

@Timoteohss

This comment has been minimized.

Copy link

@Timoteohss Timoteohss commented Oct 15, 2019

@Timoteohss

Works perfectly, but why are my headers half-transparent?

did you set background for your header view? ;)

That was it, I'm kinda stupid lol

@filipkowicz

This comment has been minimized.

Copy link
Owner Author

@filipkowicz filipkowicz commented Oct 15, 2019

Is there exist some way to handle stick header events in usual way? I mean stick header don't handle onClick events of its children or itself.

check line 41.
// handle click on sticky header -> here you should decide if you want to handle it by yourself.

@xBlackCat

This comment has been minimized.

Copy link

@xBlackCat xBlackCat commented Oct 15, 2019

check line 41.

Yep. This code just handle whole view click but any already registered onClick listeners of the item are not processed. I've tried to pass touch event to 'dispatchOnTouch' method of the item with no luck either.

I mean if the header view is complex layout with several clickable elements they will be ignored until header view is scrolled down into the list

@filipkowicz

This comment has been minimized.

Copy link
Owner Author

@filipkowicz filipkowicz commented Oct 16, 2019

@xBlackCat you need to add implementation for onTouchEvent in simple RecyclerView.SimpleOnItemTouchListener and pass event to your header there. Or override Recycler view and dispatchTouchEvent method

@RuslanNelipa

This comment has been minimized.

Copy link

@RuslanNelipa RuslanNelipa commented Nov 6, 2019

Works nice except case when first element is NOT sticky header. It draws first item as sticky then. @filipkowicz can you please suggest a solution?
I mean listof [item, header, item, item...]

I made a possible fix inside onDrawOver(). Added
if (topChildPosition == 0 && !isHeader(0)) return
But that is rather a workaround and looks terrible

@filipkowicz

This comment has been minimized.

Copy link
Owner Author

@filipkowicz filipkowicz commented Nov 6, 2019

@RuslanNelipa Please take a look at getHeaderPositionForItem method. headerPosition should be initialised with -1 and then check preformed if value is 0 or bigger. If not, do not proceed with drawing etc.. Will add fix tomorrow. Currently I’m writing from phone so sorry for formatting

@RuslanNelipa

This comment has been minimized.

Copy link

@RuslanNelipa RuslanNelipa commented Nov 14, 2019

so inside getHeaderPositionForItem() make var headerPosition = -1
and inside getHeaderViewForItem() add if (headerPosition < 0) return null
and it works now

@filipkowicz

This comment has been minimized.

Copy link
Owner Author

@filipkowicz filipkowicz commented Nov 18, 2019

added new version - using RecyclerView.NO_POSITION const. to not assuming that first item is Header
also I've created simple example how to use it. -> https://github.com/filipkowicz/HeaderItemDecorationExample

@RuslanNelipa

This comment has been minimized.

Copy link

@RuslanNelipa RuslanNelipa commented Nov 18, 2019

@filipkowicz also found an issue when you use databinding for header view. It simply doesn't bind it for some reason. I guess there's some issue with how you create header view

@filipkowicz

This comment has been minimized.

Copy link
Owner Author

@filipkowicz filipkowicz commented Nov 18, 2019

will take a look, but headers are created by adapter as it is in recycler view. See lines 84 and 86. It's working for me in my projects. Will change Example project to use bindings later so we will be able to discuss it further.
Thanks for reporting issue 🙏

that just comes to my mind:
If you are using livedata with databinding make sure you are setting lifecycleOwner for binding - that was reason for me of not working databinding some time ago

@RuslanNelipa

This comment has been minimized.

Copy link

@RuslanNelipa RuslanNelipa commented Nov 18, 2019

@filipkowicz I'm currently debugging how it works and after decorator calls 'adapter.onBindViewHolder' header's view 'TextView' remain empty.
Try to create headers with different text value using databinding.

I continue on digging the issue and will let you know if I find anything

Btw, thanks for being responsive :)

@RuslanNelipa

This comment has been minimized.

Copy link

@RuslanNelipa RuslanNelipa commented Nov 19, 2019

@filipkowicz after some investigation it looks like binding.setVariable does nothing for header when called from decorator parent.adapter?.onBindViewHolder(headerHolder, headerPosition). If I set header view without databinding everything works fine. Did you try it?

@filipkowicz

This comment has been minimized.

Copy link
Owner Author

@filipkowicz filipkowicz commented Nov 19, 2019

@RuslanNelipa I've played a little today with databinding and it works like charm :) please take a look at example version with databinding filipkowicz/HeaderItemDecorationExample#1

my guess is you are not calling ViewDataBinding::executePendingBindings after bind operation - please check it first.
Good luck!

@RuslanNelipa

This comment has been minimized.

Copy link

@RuslanNelipa RuslanNelipa commented Nov 20, 2019

@filipkowicz wow! Nice catch man. Now it works. Nice one 💪
just one remark - you need it to move to Decoration class because adapter will execute binding twice for non-header items

@sgallego

This comment has been minimized.

Copy link

@sgallego sgallego commented Dec 21, 2019

Is there any way to manage paddingTop with clipToPadding=false?

I have this recycler:

<androidx.recyclerview.widget.RecyclerView
        android:id="@+id/vRecycler"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingTop="32dp"
        android:paddingBottom="32dp"
        android:clipToPadding="false"/>

and the next image is the result. As you can see there is an initial decorator filling the padding space. How can I handle it?

itemDecoratorExample

@filipkowicz

This comment has been minimized.

Copy link
Owner Author

@filipkowicz filipkowicz commented Dec 22, 2019

@sgallego pushed new version. please take a look - 2 options - you can choose with constructor parameter shouldFadeOutHeader

@filipkowicz

This comment has been minimized.

Copy link
Owner Author

@filipkowicz filipkowicz commented Dec 22, 2019

I've updated example project too

@filipkowicz

This comment has been minimized.

@peterdk

This comment has been minimized.

Copy link

@peterdk peterdk commented Dec 24, 2019

Works great now with databinding too. Could you please lower the minSDK for the library, it's now 22 or so and I can get it to work without issue on Android 4.1 when using tools:override. I need to support low version, so please lower it to actual minimum required.

@filipkowicz

This comment has been minimized.

Copy link
Owner Author

@filipkowicz filipkowicz commented Dec 27, 2019

@peterdk check now

@SaharshPandey

This comment has been minimized.

Copy link

@SaharshPandey SaharshPandey commented Jan 20, 2020

@filipkowicz Hi, It works great, but the problem I am facing is that when I click on topmost header then the items in the background getting clicked. It is happening for the top header only. Help me if u understand it.

@TylerMcCraw

This comment has been minimized.

Copy link

@TylerMcCraw TylerMcCraw commented Mar 13, 2020

The draw for this implementation isn't working for me due to the parent.findChildViewUnder() call in onDrawOver always returning null. Any thoughts on why this would always return null?

@TylerMcCraw

This comment has been minimized.

Copy link

@TylerMcCraw TylerMcCraw commented Mar 13, 2020

Turns out, this Decoration doesn't play well if the RecyclerView has other ItemDecorations applied to it.
I've got another ItemDecoration as follows, which applies some left and right insets:

class InsetItemDecoration(@Dimension private val padding: Int) : RecyclerView.ItemDecoration() {
    override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: State) {
        super.getItemOffsets(outRect, view, parent, state)
        outRect.left = padding
        outRect.right = padding
    }
}

my RecyclerView:

        recyclerView.apply {
            adapter = this@MyFragment.adapter
            addItemDecoration(InsetItemDecoration(padding = resources.getDimensionPixelSize(R.dimen.list_margin)))
            addItemDecoration(
                StickyHeaderItemDecoration(this) { itemPosition ->
                    this@MyFragment.adapter.getItemViewType(itemPosition) == R.layout.my_header_item
                }
            )
        }
@filipkowicz

This comment has been minimized.

Copy link
Owner Author

@filipkowicz filipkowicz commented Mar 13, 2020

@TylerMcCraw please try to invert order. (will check it might be also line 61 - I'm checking if there is aby view under top right corner (with paddings)
consider replacing your decorator with simple padding added to recycler (if it's not just example)
otherwise you might want to change line 61 to parent.left + parent.width/2 to look for view at top middle instead. Good luck! If I find some free time, will take a look for some generic solution

@hantrungkien

This comment has been minimized.

Copy link

@hantrungkien hantrungkien commented Mar 30, 2020

@TylerMcCraw in my case, I use the ItemDecoration to decor the sticky headers and spacing between items.

    private val space: Int = parent.context.resources.getDimensionPixelSize(R.dimen._15dp)


    override fun onDrawOver(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) {
        super.onDrawOver(canvas, parent, state)

        val topChild = parent.getChildAt(0) ?: return

        val topChildPosition = parent.getChildAdapterPosition(topChild)
        if (topChildPosition == RecyclerView.NO_POSITION) {
            return
        }

        val headerView = getHeaderViewForItem(topChildPosition, parent) ?: return

        val contactPoint = headerView.bottom + parent.paddingTop
        val childInContact = getChildInContact(parent, contactPoint)

        if (childInContact != null && isHeader(parent.getChildAdapterPosition(childInContact))) {
            moveHeader(canvas, headerView, childInContact, parent.paddingTop)
            return
        }
        // withTranslation(...){} is a ext func in AndroidKTX
        canvas.withTranslation(0f, parent.paddingTop.toFloat()) {
            headerView.draw(this)
        }
    }


    override fun getItemOffsets(
        outRect: Rect,
        view: View,
        parent: RecyclerView,
        state: RecyclerView.State
    ) {
        super.getItemOffsets(outRect, view, parent, state)
        with(outRect) {
            val itemPosition = parent.getChildAdapterPosition(view)
            if (itemPosition == RecyclerView.NO_POSITION) {
                return
            }
            if (!isHeader(itemPosition)) {
                left = space
                right = space
            }
            bottom = space
        }
    }


    private fun getChildInContact(parent: RecyclerView, contactPoint: Int): View? {
        var childInContact: View? = null
        for (i in 0 until parent.childCount) {
            val child = parent.getChildAt(i)
            val bounds = Rect()
            parent.getDecoratedBoundsWithMargins(child, bounds)
            if (bounds.bottom > contactPoint + space) {
                if (bounds.top <= contactPoint) {
                    // This child overlaps the contactPoint
                    childInContact = child
                    break
                }
            }
        }
        return childInContact
    }

@Madina-S

This comment has been minimized.

Copy link

@Madina-S Madina-S commented Apr 16, 2020

If there are two consequent headers, the header below does not wait until the above one moves entirely to the top (both headers are with different sizes). The above header moves partially, then it gets sticked. Then after some scroll the second header gets sticked. How to fix the problem?

@peterdk

This comment has been minimized.

Copy link

@peterdk peterdk commented May 5, 2020

//val topChild = parent.getChildAt(0) ?: return
        val topChild = parent.findChildViewUnder(
            parent.paddingLeft.toFloat(),
            parent.paddingTop.toFloat() /*+ (currentHeader?.second?.itemView?.height ?: 0 )*/
        ) ?: return

I needed to uncomment topChild = parent.getChildAt(0) and comment out the findChildViewUnder line. Without that the header would disappear immediately after the first child and just worked very weird. This fixed it immediately.

@dobrowins

This comment has been minimized.

Copy link

@dobrowins dobrowins commented Jun 10, 2020

Thank you for this!

@pals-ric

This comment has been minimized.

Copy link

@pals-ric pals-ric commented Jul 8, 2020

hi @filipkowicz
i have timer in my view holder its getting reset to 0:00 while its sticking to top and after some second when i scroll more header is getting vanished.

@pals-ric

This comment has been minimized.

Copy link

@pals-ric pals-ric commented Jul 9, 2020

//val topChild = parent.getChildAt(0) ?: return
        val topChild = parent.findChildViewUnder(
            parent.paddingLeft.toFloat(),
            parent.paddingTop.toFloat() /*+ (currentHeader?.second?.itemView?.height ?: 0 )*/
        ) ?: return

I needed to uncomment topChild = parent.getChildAt(0) and comment out the findChildViewUnder line. Without that the header would disappear immediately after the first child and just worked very weird. This fixed it immediately.

worked for me .. header issues ..

@fjr619

This comment has been minimized.

Copy link

@fjr619 fjr619 commented Jul 12, 2020

how to make sticky header clickable?

@filipkowicz

This comment has been minimized.

Copy link
Owner Author

@filipkowicz filipkowicz commented Jul 13, 2020

@fjr619 it should already be clickable - please make sure you have onclick method overriden - see line 41

@fjr619

This comment has been minimized.

Copy link

@fjr619 fjr619 commented Jul 14, 2020

@filipkowicz sorry to make sure, how to override onclick? is it in our fragment/acitivty or in this headeritemdecoration? because i already have onclicklistener for my header view holder, but it didnt trigger in our sticky header, but it trigger in normal header

@ashu2451990

This comment has been minimized.

Copy link

@ashu2451990 ashu2451990 commented Jul 24, 2020

Hi.. I need to add this Itemdecorated for recycler view which is already having headers. please help me .. I am new in android developement

@pals-ric

This comment has been minimized.

Copy link

@pals-ric pals-ric commented Jul 29, 2020

i have changed color problematically but in header neighter timer is updating nor background color has been changed. its creating dummy view in header without any update which i am manipulating run time .. plz suggest changes will be very helpful

@geovannyAndrew

This comment has been minimized.

Copy link

@geovannyAndrew geovannyAndrew commented Aug 20, 2020

It is fine, but when there is click listener in the header and scrolls up it stops working :(

@Nikunj2505

This comment has been minimized.

Copy link

@Nikunj2505 Nikunj2505 commented Oct 9, 2020

How to do double sticky header in this? I mean header with sub header?

@filipkowicz

This comment has been minimized.

Copy link
Owner Author

@filipkowicz filipkowicz commented Oct 12, 2020

@Nikunj2505

How to do double sticky header in this? I mean header with sub header?

no, you can get take a look and do it kind of same way for subheaders but it will be much more complicated.
For such complicated case I would consider using CordinatorLayout with own behaviours.

@Nikunj2505

This comment has been minimized.

Copy link

@Nikunj2505 Nikunj2505 commented Oct 12, 2020

@Nikunj2505

How to do double sticky header in this? I mean header with sub header?

no, you can get take a look and do it kind of same way for subheaders but it will be much more complicated.
For such complicated case I would consider using CordinatorLayout with own behaviours.

Can you please guide me more or can you please create class to make this type of functionality?
I got below references but its deprecated and hard to maintain
https://github.com/Kenber/DoubleStickyHeadersList
https://github.com/ebarrenechea/header-decor

@ManuelEMR

This comment has been minimized.

Copy link

@ManuelEMR ManuelEMR commented Oct 15, 2020

I have a header with a button in it, I'm not being able to trigger the onClickListener of the button, how should I forward the motion event intercepted by the touchListener to the headerView itself?
I tried doing:

override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) {
                super.onTouchEvent(rv, e)
                currentHeader?.second?.itemView?.dispatchTouchEvent(e)
            }

But it doesn't work

@mfadiilahrio

This comment has been minimized.

Copy link

@mfadiilahrio mfadiilahrio commented Dec 5, 2020

Cool

@yankauskas

This comment has been minimized.

Copy link

@yankauskas yankauskas commented Dec 10, 2020

Thank you! Extremely useful!

@antanas-radzevicius-tgo

This comment has been minimized.

Copy link

@antanas-radzevicius-tgo antanas-radzevicius-tgo commented Jan 23, 2021

Thanks!

@moffpage

This comment has been minimized.

Copy link

@moffpage moffpage commented Mar 27, 2021

Thanks for the library! Could you please move it to MavenCentral since jcenter is gonna be closed for publishing soon? And after a year, fetching from.

@GWCangie

This comment has been minimized.

Copy link

@GWCangie GWCangie commented Aug 25, 2021

Hi, has it been glitching for anyone? I'll scroll up and sometimes my items will be in front of the sticky title.

@james04gr

This comment has been minimized.

Copy link

@james04gr james04gr commented Sep 7, 2021

Excellent work, thanks a lot! I have a question though.
I want to have a paddingTop on every "Header" item except the First one. So what i did is to use the getItemOffsets

`override fun getItemOffsets(
outRect: Rect,
view: View,
parent: RecyclerView,
state: RecyclerView.State
) {
super.getItemOffsets(outRect, view, parent, state)
val itemPosition = parent.getChildAdapterPosition(view)
if (itemPosition == RecyclerView.NO_POSITION) return

    val itemCount = state.itemCount
    val paddingTop = 100

    if (itemCount > 0 && itemPosition != 0
        && parent.adapter!!.getItemViewType(itemPosition) == VIEW_TYPE_HEADER)
            outRect.set(0, paddingTop,0,0)
}`

Although i get what i want and the headers have a Padding on top (except the first Header item), when a header meets the above one then the Padding space swap with the above Header and i get a mess.
Instead i get "Header1 - Padding - Header2" suddenly i have "Padding - Header1 - Header2"

Why is this happening and how can i solve that?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment