0

我正在尝试制作一个桌面应用程序,允许您搜索存储在单独目录中的 Kotlin 类中的多个预定义位置。为此,我使用了反射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”函数“状态”变量(存储所有匹配项)不是可组合函数,因此我无法更改值。

我将如何完成从另一个组件(例如按钮)更改组件(例如框)的值?

4

1 回答 1

0

在 Compose 中,您不能像使用state变量一样创建视图。您调用的结果只是Unit,当您稍后调用它时,您应该会看到一条警告“表达式未使用”。创建变量时,视图将添加到树层次结构中。

要解决您的问题,您需要将其声明display为可变状态 - 这是专门为 Compose 制作的新事物,它允许在此状态更改时触发重组:

val display by mutableStateOf<Attraction>(setOf())

然后像这样在你的更新search

val mutableDisplay = mutableSetOf<Attraction>()
// for 
// ...
mutableDisplay += temp
// ...
display = mutableDisplay

请注意,您不能在可变状态中使用可变集,因为可变状态将无法跟踪此集的更改。

要了解有关 Compose 中状态的更多信息,我建议您查看这个解释基本原则的 youtube 视频,以及 Compose心智模型,以便更好地了解如何使用它。

于 2022-03-02T18:06:18.823 回答