Single-Shot/Fire-and-Forget 用于对基本状态变化进行动画处理的动画师(animate*AsState 的单次等效))
Single-Shot/Fire-and-Forget Animator for animating basic state changes (animate*AsState's single-shot equivalent))
我只想制作一次动画,并且正在尝试不同的选项。我想使用 animate*AsState 但这不起作用,因为你必须在进入该屏幕时通过使用 LaunchedEffect 执行某种 SideEffect 来触发它,如下所示:
@Composable
fun StartAnimation(width: Float = 0f) {
var startAnimation by remember { mutableStateOf(false) }
val widthAnimation = animateDpAsState(targetValue = if(startAnimation) width.dp else 0.dp, tween(600))
Box(
modifier = Modifier
.padding(top = 30.dp)
.padding(horizontal = 30.dp)
.fillMaxWidth()
.height(20.dp)
.background(Color.Gray),
contentAlignment = Alignment.CenterStart
) {
Box(
Modifier
.background(Color.Black)
.width(widthAnimation.value)
.height(20.dp)
.background(Color.Black)
)
}
LaunchedEffect(key1 = true) {
startAnimation = true
}
}
也许有更好的方法来做到这一点,但我错过了?
我认为没有任何东西可以让您摆脱 LaunchedEffect。但这可能会更好,至少你不必使用那个人为变量:
val animatableWidth = remember { Animatable(0.dp, Dp.VectorConverter) }
LaunchedEffect(width) {
animatableWidth.animateTo(width.dp, tween(600))
}
只需创建一个自定义 fire-and-forget 系统。作为 single-shot 动画师工作,几乎可以并行生成任意多次。
@Composable
fun animateFloatAsState(
initialValue: Float,
targetValue: Float,
delay: Long = 0,
animationSpec: AnimationSpec<Float> = spring<Float>(),
visibilityThreshold: Float = 0.01f,
finishedListener: ((Float) -> Unit)? = null
): State<Float> {
var trigger by remember { mutableStateOf(false) }
return animateFloatAsState(
targetValue = if (trigger) targetValue else initialValue,
animationSpec = animationSpec,
visibilityThreshold = visibilityThreshold,
finishedListener = finishedListener
).also {
LaunchedEffect(Unit) {
delay(delay)
trigger = true
}
}
}
这适用于 Float
,但可以很容易地转换为适合 Dp
。我认为它只是将 Float
替换为 Dp
我只想制作一次动画,并且正在尝试不同的选项。我想使用 animate*AsState 但这不起作用,因为你必须在进入该屏幕时通过使用 LaunchedEffect 执行某种 SideEffect 来触发它,如下所示:
@Composable
fun StartAnimation(width: Float = 0f) {
var startAnimation by remember { mutableStateOf(false) }
val widthAnimation = animateDpAsState(targetValue = if(startAnimation) width.dp else 0.dp, tween(600))
Box(
modifier = Modifier
.padding(top = 30.dp)
.padding(horizontal = 30.dp)
.fillMaxWidth()
.height(20.dp)
.background(Color.Gray),
contentAlignment = Alignment.CenterStart
) {
Box(
Modifier
.background(Color.Black)
.width(widthAnimation.value)
.height(20.dp)
.background(Color.Black)
)
}
LaunchedEffect(key1 = true) {
startAnimation = true
}
}
也许有更好的方法来做到这一点,但我错过了?
我认为没有任何东西可以让您摆脱 LaunchedEffect。但这可能会更好,至少你不必使用那个人为变量:
val animatableWidth = remember { Animatable(0.dp, Dp.VectorConverter) }
LaunchedEffect(width) {
animatableWidth.animateTo(width.dp, tween(600))
}
只需创建一个自定义 fire-and-forget 系统。作为 single-shot 动画师工作,几乎可以并行生成任意多次。
@Composable
fun animateFloatAsState(
initialValue: Float,
targetValue: Float,
delay: Long = 0,
animationSpec: AnimationSpec<Float> = spring<Float>(),
visibilityThreshold: Float = 0.01f,
finishedListener: ((Float) -> Unit)? = null
): State<Float> {
var trigger by remember { mutableStateOf(false) }
return animateFloatAsState(
targetValue = if (trigger) targetValue else initialValue,
animationSpec = animationSpec,
visibilityThreshold = visibilityThreshold,
finishedListener = finishedListener
).also {
LaunchedEffect(Unit) {
delay(delay)
trigger = true
}
}
}
这适用于 Float
,但可以很容易地转换为适合 Dp
。我认为它只是将 Float
替换为 Dp