Search code examples
android-jetpack-composeslider

Moving Slider value based on change in ViewModel in Compose


My overall goal is to be able to set the default value of the slider to the value from within the viewModel and allow the user to slide that value. I set up the variable to save the default value like this:

val uiState by viewModel.uiState.collectAsState()
var selectedIncome by rememberSaveable { mutableStateOf(uiState.medianEarning!!.toFloat()) } 

From my understanding this creates a variable where the state is saved within the component which is needed for the slider. Then within my slider I try to update this value like this:

Text(selectedIncome.toString(),
     modifier = Modifier
                .align(Alignment.CenterHorizontally)
)

Slider(
    value = selectedIncome,
    onValueChange = { selectedIncome = it},
    valueRange = selectedIncome.times(.8f) .. selectedIncome.times(1.2f)
)

This sets the value to the default I want, however when I slide, only the text is updated and not the slider.

I tried to do it by changing the value directly in the viewModel and this method set the default value to 0 (default value within the viewModel) and after reading I realized that it won't rerender the rememberSaveable() and it is stuck in the default value of 0.

I tried the use a LaunchedEffect to force an update of the UI when uiState.medianIncome changes but this still does not update the default of the slider.


Solution

  • It is happening because valueRange of your Slider is dynamically changing together with selectedIncome value. You should make it depend on the initial value of uiState.medianEarning.

    To update selectedIncome when uiState changes, pass uiState.medianEarning as an argument to rememberSaveable. This will cause it to rerun the init block.

    val medianEarning = uiState.medianEarning!!.toFloat()
    var selectedIncome by rememberSaveable(uiState.medianEarning) { mutableFloatStateOf(medianEarning) }
    
    Slider(
        //...
        valueRange = medianEarning.times(.8f) .. medianEarning.times(1.2f)
    )