Patrick Lang
Patrick Lang

Reputation: 751

Jetpack Compose LazyColumn items scroll over stickyHeader and does not scroll to last item

I am struggling with the jetpack compose LazyColumn and the stickyHeader functionality. Basically the static view works well, but once I start scrolling, the items would go over the sticky headers, the scrolling starts a weird behaviour and the last item would never be visible as the scrolling always bounces back.

Here's how it looks like:

enter image description here

Here's the composable:

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun CollectionsScreen(
    collectionsLive: LiveData<List<CollectionsView>>,
    onCollectionChanged: (ICalCollection) -> Unit
    /* some more hoisted functions left out for simplicity */
) {

    val list by collectionsLive.observeAsState(emptyList())
    val grouped = list.groupBy { it.accountName ?: it.accountType ?: "Account" }

    LazyColumn(
        modifier = Modifier.padding(8.dp)
    ) {

        item {
            Text(
                stringResource(id = R.string.collections_info),
                textAlign = TextAlign.Center,
                modifier = Modifier.padding(bottom = 16.dp)
            )
        }

        grouped.forEach { (account, collectionsInAccount) ->
            stickyHeader {
                Text(
                    account,
                    style = MaterialTheme.typography.titleLarge,
                    fontWeight = FontWeight.Bold,
                    modifier = Modifier.padding(
                        top = 16.dp,
                        start = 8.dp,
                        end = 16.dp,
                        bottom = 8.dp
                    )
                )
            }

            items(
                items = collectionsInAccount,
                key = { collection -> collection.collectionId }
            ) { collection ->

                CollectionCard(
                    collection = collection,
                    allCollections = list,
                    onCollectionChanged = onCollectionChanged,
                    /* some more hoisted functions left out for simplicity */
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(bottom = 8.dp)
                        .animateItemPlacement()
                        .combinedClickable(
                            //onClick = { onCollectionClicked(collection) }
                         )
                )
            }
        }
    }
}

I am really not sure what is causing this issue as the code itself is pretty straightforward from the example provided in the documentation. Only the CollectionCard itself is a more complex structure. I have also tried removing the header text (the first item) and removed the Modifier.animateItemPlacement() for the card, but with no difference, the problem stays the same... The composable itself is used in a Compose View within a Fragment, but there is no nested scrolling. Do you have any idea what could cause this strange behaviour? Or might this be a bug when using cards within the LazyColumn with sticky headers?

UPDATE: It seems like the problem nothing to do with the stickyHeader, but somehow with the LazyColumn. If I replace the "stickyHeader" just with "item", the problem still persists... Only when I replace the lazyColumn with a column it would work. But I assume that there must be a solution for this problem...

Upvotes: 19

Views: 18020

Answers (5)

Giovanni Di Luca
Giovanni Di Luca

Reputation: 9

You just could replace stickyHeader{} for item{}, you will have the expected result

Upvotes: -3

Uli
Uli

Reputation: 3016

In general, if you are using Material or Material3 theming, you can wrap your stickyHeader content in a Surface to automatically make it non-transparent with your theme's standard (or customized) coloring scheme. Surface lets you raise the stickyHeader above your table's other contents.

stickyHeader {
    Surface(Modifier.fillParentMaxWidth()) {
        Text("Header")
    }
}

You can customize the Surface at your heart's desire.

I'd create another issue for the bounciness problem, it looks like a separate concern.

Upvotes: 17

Prashant Singh
Prashant Singh

Reputation: 19

Just provide a background for the sticky header.

Upvotes: -1

Oussama cherfaoui
Oussama cherfaoui

Reputation: 1

I don't know if you solved it yet, but try to fillMaxWidth and set the background. This code worked for me.

Text(
          account,
          style = MaterialTheme.typography.titleLarge,
          fontWeight = FontWeight.Bold,
          modifier = Modifier
              .padding(
                       top = 16.dp,
                       start = 8.dp,
                       end = 16.dp,
                       bottom = 8.dp
                      )
              .fillMaxWidth()
              .background(MaterialTheme.colors.background)
    )

Upvotes: 0

JL Eric
JL Eric

Reputation: 39

Setting the stickyHeader background color will help.

stickyHeader {
                Text(
                    "text",
                    modifier = Modifier.padding(
                        top = 16.dp,
                        start = 8.dp,
                        end = 16.dp,
                        bottom = 8.dp
                    )
                   .background(colorResource(id = R.color.white))
                )
            }

Upvotes: 3

Related Questions