How are we supposed to handle sticky headers in `L...
# compose
z
How are we supposed to handle sticky headers in
LazyColumn
? Either they... • Scroll under the TopAppBar sad panda • Or, if TopAppBar collapses, the sticky header will now... scroll underneath the statusBar instead sad panda I feel like its a lose-lose situation: • If I do some calculations to figure out when the sticky header is pinned at the top; and add Modifier.offset for it; theyre almost positioned correctly, but then theres a gap above them since its an offset and not padding. • If I use padding instead, the whole list behaves strangely as the padding grows. • If I add Modifier.padding (instead of using contentPadding) then that will account for my FAB (bottom padding) as well. • Additionally.. when theres padding involved, there are some glitches where the sticky headers cut each other off at different breakpoints (I havent investigated this much though). Does anyone know of a better way? I desperately need to use sticky headers for my use-case but feel like Im just chasing my own tail at this point.
p
I have not seen this effect. Are you using a
Scaffold
?
z
Yes, scaffold and then passing the padding into Lazy column.
p
Putting a
LazyColumn
with
stickyHeaders
in a
Scaffold
with a
TopAppBar
works for me both for desktop and web. In my app there are layers between the scaffold and the list, I have not tested the list as a direct child of the scaffold.
z
In my app there are layers between the scaffold and the list, I have not tested the list as a direct child of the scaffold.
I think this is the reason why it works for you; at least Im assuming that you end up in a situation where you have Modifier.padding(x) applied to the container of / directly at the LazyColumn, and not passing padding into LazyColumn(contentPadding=x)?
I know that technically works, but then you lose out on the "other" stuff that edge to edge provides, i.e. content no longer scrolls underneath the navigationBar, etc. The closest to a working solution Ive come is to create a new PaddingValues that just takes the
original - top
, so I get :
LazyColumn(contentPadding = paddingWithoutTop, modifier = Modifier.padding(top = originalPadding.calculateTop)
Which is fine I guess, but seems very awkward to remember to do in every place where sticky headers are involved.
If anyone knows a better way, Im all ears. My workaround for now is:
Copy code
@JvmInline
private value class InsetPaddingValues(
    private val original: PaddingValues,
) : PaddingValues by original {
    override fun calculateTopPadding() = Zero
}
Copy code
insetStickyHeaders: Boolean = false,
Copy code
val finalPadding = if (insetStickyHeaders) InsetPaddingValues(padding) else padding
Copy code
modifier.conditional(insetStickyHeaders) {
    padding(top = padding.calculateTopPadding())
},
So basically just insetStickyHeaders=true and the LazyColumn is now padded at the top instead of its contents.
p
Yes, this app applies Scaffold padding with Modifier.padding in all cases.
t
Not sure if my way is better but i do have a workaround for this here: https://gitlab.com/-/snippets/3604982
z
Sweet, thanks for sharing Tim. I think we had a discussion about this an eternity ago? Your solution works great, only caveat Ive ran into is that theres a tiny gap between TopAppBar & sticky header during scroll when used with
Modifier.nestedScroll
.