I have a case where I have a ViewModel that emits scroll values to a StateFlow
. Now, my Composable view should scroll to the most recent value, but I can't figure out how to achieve that.
My view model looks something like this:
class MyViewModel : ViewModel() {
private val scrollFlow = MutableStateFlow<Int>(0)
fun getScrollFlow(): StateFlow<Int> = scrollFlow.asStateFlow()
}
And my view is like this:
@Composable
fun MyScrollingView() {
val viewModel = viewModel()
val scroll by viewModel.getScrollFlow().collectAsState()
val scrollState = rememberScrollState(0)
Column(modifier = Modifier.verticalScroll(scrollState)) {
// Content here
}
}
The thing here is, how do I make the scroll state to react to the values coming from the view model?
CodePudding user response:
You can try doing it inside a LaunchedEffect
and use the scrollFlow value as its key
, every time the scrollFlow emits new value, the LaunchedEffect
will trigger its block.
@Composable
fun MyScrollingView() {
val viewModel = viewModel()
val scroll by viewModel.getScrollFlow().collectAsState()
val scrollState = rememberScrollState(0)
Column(modifier = Modifier.verticalScroll(scrollState)) {
// Content here
}
LaunchedEffect(scroll) {
scrollState.animateScrollTo(0)
//or
// scrollState.scrollTo(0)
}
}
I'm just not sure if this would work in your case especially having this statement inside your composable though.
val viewModel = viewModel()
CodePudding user response:
There are many way to achieve that, for example:
val scrollState = rememberScrollState(0)
rememberCoroutineScope().launch {
viewModel.getScrollFlow()
.flowOn(Dispatchers.Default)
.onEach{scrollVal ->
scrollState.animateScrollTo(scrollVal)
}.collect()
}
Actually I'm afraid that code could be launched on every recomposition and is not ideal so maybe:
remember{
viewModel
.getScrollFlow()
.onEach{scrollVal ->
scrollState.animateScrollTo(scrollVal)
}
}.collectAsState(0, Dispatchers.Default)
or
val scroll by viewModel.getScrollFlow().collectAsState(0, Dispatchers.Default)
LaunchedEffect(scroll){
crollState.animateScrollTo(scroll)
}