Cor*_*sby 3 android android-jetpack-compose
我有一个例子,使用单个动画浮点值来控制其他元素的动画(包括两种颜色之间的淡入淡出)会很有用。一般是否有建议的方法来执行此操作,例如声明一个其当前状态值直接由外部可变浮动状态控制的动画?例如,如果可变浮点数在特定实例中为 0.25,则它控制的所有动画都将是一个状态与另一个状态之间的 25%。
我想要这种行为的原因是强制多个动画完全同步,即使在离开和重新进入合成时也是如此。我知道过渡通常用于控制多个动画,但据我了解,这并不能确保所有子动画完美同步,即以完全相同的完成百分比。
通过使用单个可动画浮动值并使用该值直接设置 UI 元素的位置或颜色,应该可以通过暴力来实现此目的。这是最好的解决方案吗?如果我使用这种方法,我仍然需要计算两种颜色之间的插值,并且我不完全确定如何执行此操作。我尝试深入研究 Compose 源代码,以了解 animateColorAsState() 可组合项是如何完成此操作的。颜色似乎被转换为 4D 矢量,我想它们是从那里线性插值的,但我找不到执行此操作的确切代码。是否有内置函数可以在颜色或矢量之间进行插值?否则,我可以自己计算该值,但我想尝试找到一种更干净的方法来实现所有这一切。
任何想法表示赞赏!
Jetpack compose 为各种类定义了线性插值函数 ,lerp包括Rect、Color、FontSize、Size、 Offset以及除、和Shadow之外的许多类。FloatIntLong
对于最后三个,您需要添加
implementation "androidx.compose.ui:ui-util:$compose_version"
Run Code Online (Sandbox Code Playgroud)
或者您可以将它们复制粘贴为
/**
* Linearly interpolate between [start] and [stop] with [fraction] fraction between them.
*/
fun lerp(start: Float, stop: Float, fraction: Float): Float {
return (1 - fraction) * start + fraction * stop
}
/**
* Linearly interpolate between [start] and [stop] with [fraction] fraction between them.
*/
fun lerp(start: Int, stop: Int, fraction: Float): Int {
return start + ((stop - start) * fraction.toDouble()).roundToInt()
}
/**
* Linearly interpolate between [start] and [stop] with [fraction] fraction between them.
*/
fun lerp(start: Long, stop: Long, fraction: Float): Long {
return start + ((stop - start) * fraction.toDouble()).roundToLong()
}
Run Code Online (Sandbox Code Playgroud)
除了线性插值之外,有时还可以使用缩放函数将范围从 0f、1f 更改为您想要的任何范围,可以定义为
// Scale x1 from a1..b1 range to a2..b2 range
private fun scale(a1: Float, b1: Float, x1: Float, a2: Float, b2: Float) =
androidx.compose.ui.util.lerp(a2, b2, calcFraction(a1, b1, x1))
// Calculate the 0..1 fraction that `pos` value represents between `a` and `b`
private fun calcFraction(a: Float, b: Float, pos: Float) =
(if (b - a == 0f) 0f else (pos - a) / (b - a)).coerceIn(0f, 1f)
Run Code Online (Sandbox Code Playgroud)
使用这 2 个函数并结合其中一个Animatable或任意一个,animateFloatAsState您可以将多个动画与一个值同步。
在下面的示例中,lerp 和scale 用于更改卡片的矩形位置、文本大小、颜色和偏移量。
@Composable
fun SnackCard(
modifier: Modifier = Modifier,
snack: Snack,
progress: Float = 0f,
textColor: Color,
onClick: () -> Unit
) {
Box(
modifier = modifier
// Interpolate corner radius
.clip(RoundedCornerShape(lerp(20.dp, 0.dp, progress)))
.background(Color.White)
.clickable(
onClick = onClick,
interactionSource = remember { MutableInteractionSource() },
indication = null
),
contentAlignment = Alignment.TopEnd
) {
// This is lerping between .6f and 1f by changing start from 0f to .6f
val fraction = scale(0f, 1f, progress, .6f, 1f)
Image(
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxWidth()
.fillMaxHeight(fraction),
painter = rememberAsyncImagePainter(
ImageRequest.Builder(LocalContext.current).data(data = snack.imageUrl)
.apply(block = fun ImageRequest.Builder.() {
crossfade(true)
placeholder(drawableResId = R.drawable.placeholder)
}).build()
),
contentDescription = null
)
Column(
modifier = Modifier
.padding(16.dp)
.align(Alignment.BottomStart)
) {
Text(
// Interpolate Font size
fontSize = lerp(18.sp, 40.sp, progress),
// Interpolate Color
color = lerp(textColor, Color.Black, progress),
fontWeight = FontWeight.Bold,
text = snack.name
)
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
Text(
// Interpolate Font size
fontSize = lerp(12.sp, 24.sp, progress),
// Interpolate Color
color = lerp(textColor, Color.Black, progress),
text = "$${snack.price}"
)
}
}
FavoriteButton(
modifier = Modifier.graphicsLayer {
alpha = 1 - progress
}
.padding(12.dp),
color = textColor
)
}
}
Run Code Online (Sandbox Code Playgroud)
完整代码可以在这里找到
| 归档时间: |
|
| 查看次数: |
371 次 |
| 最近记录: |