In Compose I am finding no way to listen to a list when it scrolls and react accordingly.
The main goal is to change a TopAppBar
elevation according to how much the bottom list scrolls up or down; the bar elevation increases to 3 and decreases to 0 respectively, but so far I haven't even been able to listen to something as simple as the scroll of the content list below it.
This is how I have the content below the scaffold that contains the top bar:
// this is inside a composable
val scrollState = rememberScrollState()
Column(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(paddingValues)
.verticalScroll(
state = scrollState,
enabled = true,
)
) {
// multiple list items here
}
I cannot find any way to either listen to when scrollState
changes, or when the Column
scroll changes.
Available documentation shows nothing for this as far as I could find, nor could I find anything in SO either.
The only closest thing I found so far is strictly when using LazyColumn
which I am not.
I could do this incredibly easily with kotlin + xml layouts, but when it comes to compose something that should be very simple like this feels impossible, how can this be done?
You can do it with NestedScrollConnection. You need to constrain bottom value to 0 and max value to maximum allowed by scrollState.
@Preview
@Composable
fun NestedScrollSample() {
var offset by remember {
mutableStateOf(0f)
}
val scrollState = rememberScrollState()
val nestedScrollConnection = remember {
object : NestedScrollConnection {
override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
offset = (offset - available.y).coerceIn(0f, scrollState.maxValue.toFloat())
return Offset.Zero
}
}
}
Column {
Text(text = "Offset: $offset")
Column(
modifier = Modifier
.nestedScroll(nestedScrollConnection)
.fillMaxSize()
.verticalScroll(state = scrollState)
) {
repeat(100) {
Text(
modifier = Modifier
.fillMaxWidth()
.background(Color.Green)
.padding(8.dp),
text = "Row $it",
color = Color.Red,
fontSize = 20.sp
)
}
}
}
}