I have some custom composable animation that is changes value in the range [minTemperature, maxTemperature] using LaunchedEffect, and I want to trigger the animation manually. This triggered when I change the minTemperature and maxTemperature values, so I have LaunchedEffect(minTemperature, maxTemperature). But the problem is that the mutable state is triggered, ONLY WHEN THE VALUE IS CHANGED TO NEW VALUE.
So if I call the method setTemperature() the animation would not be triggered. So what I did is create new state value 'temperatureAnimationSwitch', which is switch manually with the public method startTemperatureAnimation() from the view model. So that will trigger relaunch of the LaunchedEffect.
My questions are:
- Is that the best approach using switch value?
- Is there a way to trigger the animation, when the minTemperature or maxTemperature values are changes event when set to their previous value?
- Is there a object similar to 'state, flow, livedata..', but it can be triggered, even when we change its current value to it self.
@HiltViewModel
class CityWeatherViewModel @Inject constructor(
private val getCityWeather: GetCityWeather
) : ViewModel() {
//region Temperature Component
private val _temperatureAnimationSwitch = mutableStateOf(true)
val temperatureAnimationSwitch: State<Boolean> = _temperatureAnimationSwitch
private val _minTemperature = mutableStateOf(-22f)
val minTemperature: State<Float> = _minTemperature
private val _maxTemperature = mutableStateOf(12f)
val maxTemperature: State<Float> = _maxTemperature
fun startTemperatureAnimation() {
_temperatureAnimationSwitch.value = !_temperatureAnimationSwitch.value
}
fun setTemperature(minTemperature: Float = _minTemperature.value, maxTemperature: Float = _maxTemperature.value) {
_minTemperature.value = minTemperature
_maxTemperature.value = maxTemperature
}
//endregion
}
@Composable
fun TemperatureCanvas(
viewModel: CityWeatherViewModel,
minTemperature: Float = viewModel.minTemperature.value,
maxTemperature: Float = viewModel.maxTemperature.value,
temperatureAnimationSwitch: Boolean = viewModel.temperatureAnimationSwitch.value
) {
var temperatureForText by remember { mutableStateOf(0) }
LaunchedEffect(temperatureAnimationSwitch) {
val animation = TargetBasedAnimation(
animationSpec = tween(1500),
typeConverter = Int.VectorConverter,
initialValue = minTemperature,
targetValue = maxTemperature
)
val startTime = withFrameNanos { it }
do {
val playTime = withFrameNanos { it } - startTime
temperatureForText = animation.getValueFromNanos(playTime)
} while (temperatureForText < maxTemperature)
}
// the text will be update with the animated value 'temperatureForText'
Text(text = temperatureForText)
}