Jetpack Compose具有为各种类别定义的线性内插函数lerp
,包括Rect
、Color
、FontSize
、Size
、偏移量、Shadow
以及除Float
、Int
和Long
之外的许多类别.
对于最后三个,您需要添加
implementation "androidx.compose.ui:ui-util:$compose_version"
或者,您可以将它们复制粘贴为
/**
* 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()
}
除了线性插值法之外,有时还可以将范围从0f、1f更改为您想要的任何范围的zoom 函数定义为
// 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)
使用这两个函数和一个Animatable
或任何animateFloatAsState
,您可以用一个值同步多个动作.
在下面的示例中,LERP和Scale用于更改矩形的位置、文本大小、 colored颜色 和卡片的偏移量.
@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
)
}
}
完整的代码可以在这里找到
https://github.com/SmartToolFactory/Jetpack-Compose-Tutorials/blob/master/Tutorial1-1Basics/src/main/java/com/smarttoolfactory/tutorial1_1basics/chapter6_graphics/Tutorial6_30LinearInterpolation.kt个