Android Jetpack Compose(可组合)手动触发更改
Android Jetpack Compose (Composable) Trigger Change Manually
我有一些自定义的可组合动画,它使用 LaunchedEffect 在 [minTemperature, maxTemperature] 范围内更改值,我想手动触发动画。这在我更改 minTemperature 和 maxTemperature 值时触发,因此我有 LaunchedEffect(minTemperature, maxTemperature)。但问题是只有当值更改为新值时才会触发可变状态。
因此,如果我调用 setTemperature() 方法,则不会触发动画。所以我所做的是创建新的状态值 'temperatureAnimationSwitch',这是使用视图模型中的 public 方法 startTemperatureAnimation() 手动切换的。因此,这将触发 LaunchedEffect 的重新启动。
我的问题是:
- 这是使用开关值的最佳方法吗?
- 当 minTemperature 或 maxTemperature 值设置为之前的值时更改事件是否有触发动画的方法?
- 有没有类似'state, flow, livedata..'的对象,但是它可以被触发,即使我们自己改变它的当前值。
@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)
}
我认为你需要设置 SnapshotMutationPolicy
of State object to neverEqualPolicy()
。这将报告对该对象的所有写入,无论该值是否更改。
private val _minTemperature = mutableStateOf(-22f, neverEqualPolicy())
private val _maxTemperature = mutableStateOf(12f, neverEqualPolicy())
我有一些自定义的可组合动画,它使用 LaunchedEffect 在 [minTemperature, maxTemperature] 范围内更改值,我想手动触发动画。这在我更改 minTemperature 和 maxTemperature 值时触发,因此我有 LaunchedEffect(minTemperature, maxTemperature)。但问题是只有当值更改为新值时才会触发可变状态。
因此,如果我调用 setTemperature() 方法,则不会触发动画。所以我所做的是创建新的状态值 'temperatureAnimationSwitch',这是使用视图模型中的 public 方法 startTemperatureAnimation() 手动切换的。因此,这将触发 LaunchedEffect 的重新启动。
我的问题是:
- 这是使用开关值的最佳方法吗?
- 当 minTemperature 或 maxTemperature 值设置为之前的值时更改事件是否有触发动画的方法?
- 有没有类似'state, flow, livedata..'的对象,但是它可以被触发,即使我们自己改变它的当前值。
@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)
}
我认为你需要设置 SnapshotMutationPolicy
of State object to neverEqualPolicy()
。这将报告对该对象的所有写入,无论该值是否更改。
private val _minTemperature = mutableStateOf(-22f, neverEqualPolicy())
private val _maxTemperature = mutableStateOf(12f, neverEqualPolicy())