我一直在玩Jetpack Compose Desktop.我注意到一些我真的不明白的事情:

import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application

@Composable
@Preview
fun App() {
    var text by mutableStateOf("Hello, World!")

    MaterialTheme {
        TextField(text, onValueChange = { text = it })
        Button(onClick = {
            text = "Hello, Desktop!"
        }) {
            Text(text)
        }
    }
}

fun main() = application {
    Window(onCloseRequest = ::exitApplication) {
        App()
    }
}

Why am I able to change the text in the TextField? I thought, that on every recompose the mutable state get reinstanciated with the initial Value: so the Text should not be able to change

import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.layout.Column
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application

@Composable
@Preview
fun App() {
    var text by mutableStateOf("Hello, World!")

    Column {
        TextField(text, onValueChange = { text = it })
        Button(onClick = {
            text = "Hello, Desktop!"
        }) {
            Text(text)
        }
    }
}

fun main() = application {
    Window(onCloseRequest = ::exitApplication) {
        App()
    }
}

然而,如果你用一列替换MaterialTheme,它会像预期的那样工作,你无法更改TextField中的文本.

为什么?这是一个bug还是一个特性?

推荐答案

It's a feature of Compose about scoping and smart recomposition. You can check my detailed answer here.

真正让你的整个作品可以重组的是Column个有inline个关键词.

@Composable
inline fun Column(
    modifier: Modifier = Modifier,
    verticalArrangement: Arrangement.Vertical = Arrangement.Top,
    horizontalAlignment: Alignment.Horizontal = Alignment.Start,
    content: @Composable ColumnScope.() -> Unit
) {
    val measurePolicy = columnMeasurePolicy(verticalArrangement, horizontalAlignment)
    Layout(
        content = { ColumnScopeInstance.content() },
        measurePolicy = measurePolicy,
        modifier = modifier
    )
}

比如说,你有一个可组合设置背景 colored颜色 最初在组成和变化在每个重新组合,这创造了自己的范围.不带内联的Lambda被视为作用域.

@Composable
fun RandomColorColumn(content: @Composable () -> Unit) {

    Column(
        modifier = Modifier
            .padding(4.dp)
            .shadow(1.dp, shape = CutCornerShape(topEnd = 8.dp))
            .background(getRandomColor())
            .padding(4.dp)
    ) {
        content()
    }
}

With

@Composable
fun App2() {
    var text by mutableStateOf("Hello, World!")

    RandomColorColumn {
        TextField(text, onValueChange = { text = it })
        Button(onClick = {
            text = "Hello, Desktop!"
        }) {
            Text(text)
        }
    }
}

还有一个是Column

@Composable
fun App() {
    var text by mutableStateOf("Hello, World!")

    Column(modifier = Modifier.background(getRandomColor())) {
        TextField(text, onValueChange = { text = it })
        Button(onClick = {
            text = "Hello, Desktop!"
        }) {
            Text(text)
        }
    }
}

随机色函数

fun getRandomColor() =  Color(
    red = Random.nextInt(256),
    green = Random.nextInt(256),
    blue = Random.nextInt(256),
    alpha = 255
)

You will see that Column background color will change every time you change text but not with App2()

enter image description here

Kotlin相关问答推荐

Spring Boot kotlin协程不能并行运行

S使用MAP和ElseThrow的习惯用法是什么?

用Quarkus和Reactor重写异步过滤器中的数据流

如何在 Spring Boot 3 中为内部类提供运行时提示

Kotlin 中的as Long和.toLong()有什么区别?

在 Kotlin 协程中切换 IO 和 UI 的正确方法是什么?

从 HashMap 检索时的 NPE,即使 containsKey() 在多线程环境中返回 true

将 Completable 转换为 Single 的规范方法?

API 'variant.getJavaCompile()' 已过时

Kotlin 顶级函数与对象函数

如何使用kotlin中的反射查找包中的所有类

main函数和常规函数有什么区别?

当被Spring代理类访问时,Kotlin实例变量为null

Kotlin reflect proguard SmallSortedMap

内联 Kotlin 方法没有覆盖报告

kotlin中密封类和密封接口的区别是什么

Recyclerview: listen to padding click events

Java的Kotlin:字段是否可以为空?

如何在 Kotlin 中将串联转换为模板

RxJava - 每秒发出一个 observable