下面的代码可以正常工作:每当用户单击canvas本身或单击topBar图标时,canvas都将重新组合,无论单击次数或顺序如何。此外,state变量值揭示了我想知道的一些信息:用户单击的位置。(值0和1表示单击了图标,值2和3表示画布)。
但是,如果canvasState和iconState变量被设置为各自的V1函数而不是V2函数,则不会检测到连续多次单击画布或图标,这显然是因为V1函数可以重新将相同的值赋给状态变量,这与V2函数不同。
因为我使用的是neverEqualPolicy(),所以我想我不必给状态变量赋一个不同的值来触发重组。作为Kotlin和Compose的新手,我误解了什么?
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyApp()
}
}
}
@Composable
fun MyApp() {
var state by remember { mutableStateOf(value = 0, policy = neverEqualPolicy()) }
val canvasStateV1 = { state = 0 }
val iconStateV1 = { state = 2 }
val canvasStateV2 = { state = if (state == 0) { 1 } else { 0 } }
val iconStateV2 = { state = if (state == 2) { 3 } else { 2 } }
val iconState = iconStateV2
val canvasState = canvasStateV2
Scaffold(
topBar = { TopBar(canvasState) },
content = { padding ->
Column(Modifier.padding(padding)) {
Screen(state, iconState)
}
}
)
}
@Composable
fun TopBar(iconState: () -> Unit) {
TopAppBar(
title = { Text("This is a test") },
actions = {
IconButton(onClick = { iconState() }) {
Icon(Icons.Filled.AddCircle, null)
}
}
)
}
@Composable
fun Screen(state: Int, canvasState: () -> Unit) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Box(
modifier = Modifier
.aspectRatio(ratio = 1f)
.background(color = MaterialTheme.colors.onSurface)
.pointerInput(Unit) {
detectTapGestures(
onTap = { canvasState() },
)
}
) {
Canvas(
modifier = Modifier.fillMaxSize().clipToBounds()
) {
Log.d("Debug", "Canvas: state = $state")
}
}
}
}
我不知道还有什么可以让neverEqualPolicy()按预期工作。
1条答案
按热度按时间lrl1mhuk1#
我认为这主要是因为函数Screen()是可跳过的。如果您将状态添加为MutableState而不是Int本身,您将看到每次状态值更新时都会调用Log.d。将Screen()函数合并到MyApp中的Column也是如此
Compose在构建时分析每个函数。screen函数接收一个整数值,这是一个不可变的值,所以函数本身是可以跳过的。
要分析哪些函数是可跳过/稳定的(哪些不是),您可以在构建阶段运行一个报告。
**EDIT:**在本例中,您有两个按钮,一个更改值,一个设置相同的值。当设置相同的值时,您只能看到本地重组的Log.d。当更改状态值时,您可以看到两个日志行。本地和外部都经过重组。
您也可以传递mutableState而不是int值本身,当您传递mutableState时,neverEqualPolicy仍然有效。