Hello, I am implementing smooth scroll to top func...
# compose
z
Hello, I am implementing smooth scroll to top functionality, but the call to scroll to the top comes from outside compose land. Is this a proper way to use a LaunchedEffect?
Copy code
if (viewModel.state.scrollToTop) {
    LaunchedEffect(viewModel.state.scrollToTop) {
        scrollState.animateScrollTo(0)
        viewModel.updateScrollToTop(false)
    }
  }
s
this works fine
Better: hoist scroll state to the same place the event is generated
z
🤯 ahhh nice. I will give that a shot
thank you!
I’ve been struggling to hoist the scroll state, do you know of any examples on how to achieve it?
s
You can construct it with the public constructor anywhere https://developer.android.com/reference/kotlin/androidx/compose/foundation/ScrollState#ScrollState(kotlin.Int) You can save it using SavedState outside of composition using .saveable
note that
rememberScrollState
is really just doing all of this in composition using
remember
, but there's no composition specific bits to a ScrollState
Copy code
@Composable
fun rememberScrollState(initial: Int = 0): ScrollState {
    return rememberSaveable(saver = ScrollState.Saver) {
        ScrollState(initial = initial)
    }
}
z
ah is this assuming I’m using the androix ViewModel? I’m just using plain old kotlin object and calling it a view model
s
Ah that's fine
you'll have to do something to wire up saving if you want that, but otherwise you can just hold a ScrollState object anywhere
z
essentially what I’m trying to do is… • I have a container
View
for my whole page that extends
AbstractComposeView
• In the
onSaveInstanceState
and
restoreInstanceState
methods I’m trying to stuff the scroll position into a parcelable and then restore it • I can save and fetch the value just fine, but when trying to restore it I’m properly setting the scroll position once, but then it gets written again to 0 for reasons I don’t understand yet
z
does that only trigger when rotation and activity recreation are done? I’m trying to save the state when hitting back from another page
s
oic
either way, looking at impl, all it does is construct another ScrollState(), so I'd guess you're somehow clobbering it after restore
Copy code
val Saver: Saver<ScrollState, *> = Saver(
            save = { it.value },
            restore = { ScrollState(it) }
        )
z
yeah I need to figure out why its getting overwritten
thanks for the pointers!
s
the resetting to 0 is implying to me that something is resetting the state, perhaps when a effect is created in composition?
z
I figured out why it was reset to zero and tried this out:
Copy code
val position = viewModel.state.scrollPosition
val scrollState = rememberScrollState(position)
However the initial position via remember is only set once and ignored when recomposing. So I tried to force a scroll via:
Copy code
LaunchedEffect(viewModel.state.scrollPosition) {
  scrollState.scrollTo(position)
}
This does scroll the view, however since the composable hasn’t laid out yet it tries to scroll to a position that’s off the screen so you end up only partway down.
s
Why not just put the ScrollState itself in
viewModel.state
?
z
good point I could simplify that, I did this:
Copy code
val scrollState = viewModel.state.scrollState

 
  Column(
    modifier = Modifier
      .verticalScroll(scrollState)
      .padding(bottom = AffirmTheme.dimensions.screenVerticalSmallMargin)
  )
However its the same issue where the view shifts down only a little bit despite being given a value like 1900
do I have to somehow wait until after the view has been composed before I try to update the scroll position?
yeah if I wait 1 second before updating the scroll state, it scrolls to the correct position
s
Are you composing with an empty list the first frame by any chance?
z
I’m not, even before the data is loaded there are placeholder values
s
I'd say try to extract a repro and file that one. You could be hitting an init path that has an issue, unclear
z
👍 will do, thank you again for your responsiveness and help! It’s very much appreciated
206 Views