Pio*_*per 5 kotlin android-jetpack-compose jetpack-compose-animation compose-recomposition
我正在尝试使用 Jetpack Compose 在我的 Android 应用程序中创建天空视图。我想将它显示在Card带有固定的height. 在晚上,卡片背景变成深蓝色,我希望天空中散布一些闪烁的星星。
为了创建星星闪烁动画,我使用了一个InfiniteTransition对象和一个应用于多个s 的scale属性。这些s 在 a 内部创建,然后使用循环随机传播。我正在使用的完整代码如下所示:animateFloatIconIconBoxWithConstraintsfor
@Composable
fun NightSkyCard() {
Card(
modifier = Modifier
.height(200.dp)
.fillMaxWidth(),
elevation = 2.dp,
shape = RoundedCornerShape(20.dp),
backgroundColor = DarkBlue
) {
val infiniteTransition = rememberInfiniteTransition()
val scale by infiniteTransition.animateFloat(
initialValue = 1f,
targetValue = 0f,
animationSpec = infiniteRepeatable(
animation = tween(1000),
repeatMode = RepeatMode.Reverse
)
)
BoxWithConstraints(
modifier = Modifier.fillMaxSize()
) {
for (n in 0..20) {
val size = Random.nextInt(3, 5)
val start = Random.nextInt(0, maxWidth.value.toInt())
val top = Random.nextInt(10, maxHeight.value.toInt())
Icon(
imageVector = Icons.Filled.Circle,
contentDescription = null,
modifier = Modifier
.padding(start = start.dp, top = top.dp)
.size(size.dp)
.scale(scale),
tint = Color.White
)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
这段代码的问题是 的BoxWithConstraints范围不断重组,所以我得到很多点从屏幕上快速出现和消失。我希望范围只运行一次,以便第一次创建的点会使用scale属性动画闪烁。我怎样才能做到这一点?
您应该寻找最少量的重组来实现您的目标,而不是持续重组。
\nCompose 有 3 个阶段。构图、布局和绘图,官方文档中有解释。当您使用 lambda 时,您会将状态读取从组合阶段推迟到布局或绘制阶段。
\n如果使用Modifier.scale()或Modifier.offset()以上三个阶段都被调用。如果您使用Modifier.graphicsLayer{scale}或Modifier.offset{}推迟状态读取到布局阶段。最好的部分是,如果您使用Canvas,这是一个在引擎盖下的Spacerwith ,您可以推迟状态读取到绘制阶段,如下例所示,并且您只需使用 1 个构图即可实现目标,而不是在每一帧上重新构图。Modifier.drawBehind{}
例如来自官方文档
\n// Here, assume animateColorBetween() is a function that swaps between\n// two colors\nval color by animateColorBetween(Color.Cyan, Color.Magenta)\n\nBox(Modifier.fillMaxSize().background(color))\nRun Code Online (Sandbox Code Playgroud)\n\n\n这里盒子的背景颜色在两种颜色之间快速切换。因此,这种状态变化非常频繁。然后可组合项在后台修改器中读取此状态。因此,框\n必须在每一帧上重新组合,因为颜色在每一帧上\n都在变化。
\n为了改善这一点,我们可以使用基于 lambda 的修饰符\xe2\x80\x93(在本例中为\ndrawBehind)。这意味着颜色状态仅在绘制阶段读取。因此,Compose 可以完全跳过合成和布局阶段\n\n\xe2\x80\x93,当颜色发生变化时,Compose 直接进入绘制\n阶段。
\n
val color by animateColorBetween(Color.Cyan, Color.Magenta)\nBox(\n Modifier\n .fillMaxSize()\n .drawBehind {\n drawRect(color)\n }\n)\nRun Code Online (Sandbox Code Playgroud)\n以及如何实现您的成果
\n@Composable\nfun NightSkyCard2() {\n Card(\n modifier = Modifier\n .height(200.dp)\n .fillMaxWidth(),\n elevation = 2.dp,\n shape = RoundedCornerShape(20.dp),\n backgroundColor = Color.Blue\n ) {\n val infiniteTransition = rememberInfiniteTransition()\n val scale by infiniteTransition.animateFloat(\n initialValue = 1f,\n targetValue = 0f,\n animationSpec = infiniteRepeatable(\n animation = tween(1000),\n repeatMode = RepeatMode.Reverse\n )\n )\n\n val stars = remember { mutableStateListOf<Star>() }\n\n\n BoxWithConstraints(\n modifier = Modifier\n .fillMaxSize()\n .background(Color.Blue)\n ) {\n\n SideEffect {\n println(" Recomposing")\n }\n \n LaunchedEffect(key1 = Unit) {\n repeat(20) {\n stars.add(\n Star(\n Random.nextInt(2, 5).toFloat(),\n Random.nextInt(0, constraints.maxWidth).toFloat(),\n Random.nextInt(10, constraints.maxHeight).toFloat()\n )\n )\n }\n }\n \n Canvas(modifier = Modifier.fillMaxSize()) {\n if(stars.size == 20){\n stars.forEach { star ->\n drawCircle(\n Color.White,\n center = Offset(star.xPos, star.yPos),\n radius = star.radius *(scale)\n )\n }\n }\n }\n }\n }\n}\n\n@Immutable\ndata class Star(val radius: Float, val xPos: Float, val yPos: Float)\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
2441 次 |
| 最近记录: |