use*_*421 3 android-jetpack-compose compose-recomposition
我正在为我的应用程序创建一个自定义滑块控件,但如果不添加一些丑陋的黑客,我无法避免不必要的重组......
CustomSlider1是一个当值改变时重组其所有子组件的组件;CustomSlider2是我想出的,但代码似乎不正确,所以有人可以告诉我我做错了什么CustomSlider1以及是否CustomSlider2确实正确?
这两个组件之间的区别基本上是我通过 lambda 读取值,并将组件添加到ScopedSlider可组合项中。
我正在使用recomposeHighlighter来显示重组。
这是代码:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
TestTheme {
Column {
var value by remember {
mutableStateOf(50f)
}
CustomSlider1("Custom Slider", value, 50f, true, { value = it }, 0f..100f, 5)
Spacer(modifier = Modifier.padding(10.dp))
CustomSlider2("Custom Slider 2", { value }, 50f, true, { value = it }, 0f..100f, 5)
}
}
}
}
}
@Composable
fun CustomSlider1(
label: String,
value: Float,
defaultValue: Float,
enabled: Boolean = true,
onValueChange: (Float) -> Unit,
valueRange: ClosedFloatingPointRange<Float>,
steps: Int = 0,
) {
Column(
modifier = Modifier.recomposeHighlighter()
) {
Text(
text = label,
color = if (enabled) Color.Unspecified else LocalContentColor.current.copy(alpha = 0.5f),
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.recomposeHighlighter()
)
Row {
Slider(
value = value,
valueRange = valueRange,
steps = steps,
enabled = enabled,
onValueChange = onValueChange,
modifier = Modifier
.recomposeHighlighter()
.weight(1f)
)
IconButton(
onClick = { onValueChange(defaultValue) },
enabled = enabled,
colors = IconButtonDefaults.iconButtonColors(contentColor = MaterialTheme.colorScheme.primary),
modifier = Modifier.recomposeHighlighter()
) {
Icon(
imageVector = Icons.Filled.Refresh,
contentDescription = null,
modifier = Modifier.recomposeHighlighter()
)
}
}
}
}
@Composable
fun CustomSlider2(
label: String,
value: () -> Float,
defaultValue: Float,
enabled: Boolean = true,
onValueChange: (Float) -> Unit,
valueRange: ClosedFloatingPointRange<Float>,
steps: Int = 0,
) {
Column(
modifier = Modifier.recomposeHighlighter()
) {
Text(
text = label,
color = if (enabled) Color.Unspecified else LocalContentColor.current.copy(alpha = 0.5f),
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.recomposeHighlighter()
)
Row {
Scoped { //had to do this to avoid recompositions...
Slider(
value = value.invoke(),
valueRange = valueRange,
steps = steps,
enabled = enabled,
onValueChange = onValueChange,
modifier = Modifier
.recomposeHighlighter()
.weight(1f)
)
}
IconButton(
onClick = { onValueChange(defaultValue) },
enabled = enabled,
colors = IconButtonDefaults.iconButtonColors(contentColor = MaterialTheme.colorScheme.primary),
modifier = Modifier.recomposeHighlighter()
) {
Icon(
imageVector = Icons.Filled.Refresh,
contentDescription = null,
modifier = Modifier.recomposeHighlighter()
)
}
}
}
}
@Composable
fun Scoped(content: @Composable () -> Unit) = content()
Run Code Online (Sandbox Code Playgroud)
为了防止重组,您要做的第一件事是创建范围来创建重组范围以限制重组,因为 Column 和 Row 是不创建范围的内联函数。
\n关于 lambda 的第二件事。在组合中,lambda 是独一无二的,它们将状态读取从框架的组合阶段推迟到布局或绘制阶段,这就是您不需要重新组合的原因。
\nComposition->Layout(measure 和 Layout)->Draw 是使用 lambda 触发(重新)组合的阶段,您不调用组合阶段。
\n对于 lambda 和状态延迟,您可以查看下面的官方文档或问题
\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) Box( Modifier\n .fillMaxSize()\n .drawBehind {\n drawRect(color)\n } )\nRun Code Online (Sandbox Code Playgroud)\nAndroid Jetpack Compose - 每次文本字段值更改时可组合函数都会重新组合
\n对于范围合成,您可以查看此问题或与其链接的其他答案
\n| 归档时间: |
|
| 查看次数: |
4053 次 |
| 最近记录: |