我可以通过 Compose Multiplatform 中的单独按钮更改组件的值吗?
Can I change the value of a component from a separate button in Compose Multiplatform?
我正在尝试制作一个桌面应用程序,允许您在单独的目录中搜索存储在 Kotlin 类 中的多个预定义位置。为此,我使用了 reflections and compose-jb 库。
我 运行 遇到的问题是,当我输入标签后按下搜索按钮时,我无法弄清楚如何更新方框列(位于另一个方框组件中)以进行更改我要搜索。
下面是我的代码(针对 Main.kt 文件),它描述了整个桌面应用程序。
val reflections = Reflections("io.github.mobomega.project.attractions")
var display = mutableSetOf<Attraction>()
fun main() = application {
val stateVertical = rememberScrollState(0)
val stateHorizontal = rememberScrollState(0)
var state = Box(
modifier = Modifier
.fillMaxSize()
.verticalScroll(stateVertical)
.padding(end = 12.dp, bottom = 12.dp)
.horizontalScroll(stateHorizontal)
)
Window(
onCloseRequest = ::exitApplication,
title = "Search",
state = rememberWindowState(width = 2256.dp, height = 1504.dp)
) {
val count = remember { mutableStateOf(1) }
MaterialTheme {
Column {
val text = remember { mutableStateOf("") }
OutlinedTextField(
value = text.value,
singleLine = true,
onValueChange = { text.value = it },
modifier = Modifier.align(Alignment.CenterHorizontally)
)
Row (modifier = Modifier.size(2256.dp, 50.dp), horizontalArrangement = Arrangement.Center) {
Button(modifier = Modifier.align(Alignment.Top),
onClick = {
val tags = text.value.split(", ", ",")
for (tag in tags) {
search(tag.lowercase())
println("$display have tag $tag")
}
// Setting the new value of the Box
state = create(stateVertical, stateHorizontal)
// Creates error:
// "@Composable invocations can only happen from the context of a @Composable function"
}) {
Text("Search")
}
Button (modifier = Modifier.align(Alignment.Top),
onClick = {
display.clear()
}) {
Text("Reset")
}
}
Row (horizontalArrangement = Arrangement.Center) {
Box(
modifier = Modifier.fillMaxSize()
.background(color = Color(red = 0xFF, green = 0xFF, blue = 0xFF))
.padding(10.dp)
) {
state // Creating the state Box component in the Row
VerticalScrollbar(
modifier = Modifier.align(Alignment.CenterEnd)
.fillMaxHeight(),
adapter = rememberScrollbarAdapter(stateVertical)
)
HorizontalScrollbar(
modifier = Modifier.align(Alignment.BottomStart)
.fillMaxWidth()
.padding(end = 12.dp),
adapter = rememberScrollbarAdapter(stateHorizontal)
)
}
}
}
}
}
}
@Composable
fun textBox(text: String = "Item") {
Box(
modifier = Modifier.height(32.dp)
.width(400.dp)
.background(color = Color(200, 0, 0, 20))
.padding(start = 10.dp),
contentAlignment = Alignment.CenterStart
) {
Text(text = text)
}
}
@Composable
fun create(stateVertical: ScrollState, stateHorizontal: ScrollState) = Box(
modifier = Modifier
.fillMaxSize()
.verticalScroll(stateVertical)
.padding(end = 12.dp, bottom = 12.dp)
.horizontalScroll(stateHorizontal)
) {
Column {
var x = 0
for (attr in display) {
x++
textBox(attr.name)
if (x < display.size) {
Spacer(modifier = Modifier.height(5.dp).align(Alignment.CenterHorizontally))
}
}
}
}
fun search(text: String) {
for (attr in reflections.getSubTypesOf(Attraction::class.java)) {
val temp = attr.getConstructor().newInstance()
println("${temp.name} has tags ${temp.tags}")
if (temp.matches(text) && (temp !in display)) {
display += temp
}
}
}
我已尝试更新包含所有符合任何搜索条件的项目的 Box 的值,但我 运行 遇到了一些问题,例如“onClick”功能我在其中设置了“状态”变量的新值(存储所有匹配项)不是可组合函数,因此我无法更改该值。
如何从另一个组件(例如 Button)更改 Component(例如 Box)的值?
在 Compose 中,您无法像使用 state
变量那样创建视图。您调用的结果只是 Unit
,当您稍后调用它时,您应该会看到一条警告“表达式未使用”。创建变量时,视图将添加到树层次结构中。
要解决您的问题,您需要将 display
声明为可变状态 - 这是专为 Compose 制作的新事物,它允许在此状态更改时触发重组:
val display by mutableStateOf<Attraction>(setOf())
然后在您的 search
中像这样更新:
val mutableDisplay = mutableSetOf<Attraction>()
// for
// ...
mutableDisplay += temp
// ...
display = mutableDisplay
请注意,您不能在可变状态中使用可变集,因为可变状态将无法跟踪此集的更改。
要了解有关 Compose 中的状态的更多信息,我建议您查看 this youtube video which explains the basic principles, and Compose mental model 以更好地了解如何使用它。
我正在尝试制作一个桌面应用程序,允许您在单独的目录中搜索存储在 Kotlin 类 中的多个预定义位置。为此,我使用了 reflections and compose-jb 库。
我 运行 遇到的问题是,当我输入标签后按下搜索按钮时,我无法弄清楚如何更新方框列(位于另一个方框组件中)以进行更改我要搜索。
下面是我的代码(针对 Main.kt 文件),它描述了整个桌面应用程序。
val reflections = Reflections("io.github.mobomega.project.attractions")
var display = mutableSetOf<Attraction>()
fun main() = application {
val stateVertical = rememberScrollState(0)
val stateHorizontal = rememberScrollState(0)
var state = Box(
modifier = Modifier
.fillMaxSize()
.verticalScroll(stateVertical)
.padding(end = 12.dp, bottom = 12.dp)
.horizontalScroll(stateHorizontal)
)
Window(
onCloseRequest = ::exitApplication,
title = "Search",
state = rememberWindowState(width = 2256.dp, height = 1504.dp)
) {
val count = remember { mutableStateOf(1) }
MaterialTheme {
Column {
val text = remember { mutableStateOf("") }
OutlinedTextField(
value = text.value,
singleLine = true,
onValueChange = { text.value = it },
modifier = Modifier.align(Alignment.CenterHorizontally)
)
Row (modifier = Modifier.size(2256.dp, 50.dp), horizontalArrangement = Arrangement.Center) {
Button(modifier = Modifier.align(Alignment.Top),
onClick = {
val tags = text.value.split(", ", ",")
for (tag in tags) {
search(tag.lowercase())
println("$display have tag $tag")
}
// Setting the new value of the Box
state = create(stateVertical, stateHorizontal)
// Creates error:
// "@Composable invocations can only happen from the context of a @Composable function"
}) {
Text("Search")
}
Button (modifier = Modifier.align(Alignment.Top),
onClick = {
display.clear()
}) {
Text("Reset")
}
}
Row (horizontalArrangement = Arrangement.Center) {
Box(
modifier = Modifier.fillMaxSize()
.background(color = Color(red = 0xFF, green = 0xFF, blue = 0xFF))
.padding(10.dp)
) {
state // Creating the state Box component in the Row
VerticalScrollbar(
modifier = Modifier.align(Alignment.CenterEnd)
.fillMaxHeight(),
adapter = rememberScrollbarAdapter(stateVertical)
)
HorizontalScrollbar(
modifier = Modifier.align(Alignment.BottomStart)
.fillMaxWidth()
.padding(end = 12.dp),
adapter = rememberScrollbarAdapter(stateHorizontal)
)
}
}
}
}
}
}
@Composable
fun textBox(text: String = "Item") {
Box(
modifier = Modifier.height(32.dp)
.width(400.dp)
.background(color = Color(200, 0, 0, 20))
.padding(start = 10.dp),
contentAlignment = Alignment.CenterStart
) {
Text(text = text)
}
}
@Composable
fun create(stateVertical: ScrollState, stateHorizontal: ScrollState) = Box(
modifier = Modifier
.fillMaxSize()
.verticalScroll(stateVertical)
.padding(end = 12.dp, bottom = 12.dp)
.horizontalScroll(stateHorizontal)
) {
Column {
var x = 0
for (attr in display) {
x++
textBox(attr.name)
if (x < display.size) {
Spacer(modifier = Modifier.height(5.dp).align(Alignment.CenterHorizontally))
}
}
}
}
fun search(text: String) {
for (attr in reflections.getSubTypesOf(Attraction::class.java)) {
val temp = attr.getConstructor().newInstance()
println("${temp.name} has tags ${temp.tags}")
if (temp.matches(text) && (temp !in display)) {
display += temp
}
}
}
我已尝试更新包含所有符合任何搜索条件的项目的 Box 的值,但我 运行 遇到了一些问题,例如“onClick”功能我在其中设置了“状态”变量的新值(存储所有匹配项)不是可组合函数,因此我无法更改该值。
如何从另一个组件(例如 Button)更改 Component(例如 Box)的值?
在 Compose 中,您无法像使用 state
变量那样创建视图。您调用的结果只是 Unit
,当您稍后调用它时,您应该会看到一条警告“表达式未使用”。创建变量时,视图将添加到树层次结构中。
要解决您的问题,您需要将 display
声明为可变状态 - 这是专为 Compose 制作的新事物,它允许在此状态更改时触发重组:
val display by mutableStateOf<Attraction>(setOf())
然后在您的 search
中像这样更新:
val mutableDisplay = mutableSetOf<Attraction>()
// for
// ...
mutableDisplay += temp
// ...
display = mutableDisplay
请注意,您不能在可变状态中使用可变集,因为可变状态将无法跟踪此集的更改。
要了解有关 Compose 中的状态的更多信息,我建议您查看 this youtube video which explains the basic principles, and Compose mental model 以更好地了解如何使用它。