单击按钮时 TextField 值发生变化

问题描述 投票:0回答:1

我是一名初级程序员,正在创建一个足球应用程序来模拟锦标赛的小组赛阶段。然而,我遇到了一个我无法处理的问题。我创建了一个屏幕,顶部有用于更改组的按钮,但是当我更改组时,ScoreInput 字段(它是 OutlinedTextField)具有上一个组中的值,我希望这些值成为初始值,即 0:0。我意识到这仍然是同一个 TextField,我只是更改了旁边显示的团队,但我不知道如何解决这个问题(创建 6 个看起来相同的单独屏幕似乎也不是一个好的选择)给我的想法)。我还意识到应用程序不应该在 UI 层包含太多逻辑,尽管我想在稍后阶段进行优化。 我希望有人可以帮助我,并提前非常感谢您的帮助。

此外,需要保留用户无法在同一组中编辑已批准结果的选项,只有在更改组后才能进行后续申请阶段

我的屏幕代码:

@Composable
fun GroupStageScreen(viewModel: EuroViewModel) {
    val groups = listOf("A", "B", "C", "D", "E", "F")
    val (matchResult, setMatchResult) = remember { mutableStateOf(MutableList(6) { EuroMatchResult(0, 0) })  }
    val groupData by viewModel.groupData.collectAsState(emptyList())
    val (selectedGroup, setSelectedGroup) = remember { mutableStateOf(groups[0]) }

    Surface(
        modifier = Modifier.fillMaxSize(),
        color = background_color
    ) {
        Column(
            verticalArrangement = Arrangement.Top,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            // Buttons for changing groups
            Row(
                modifier = Modifier
                    .padding(5.dp)
                    .padding(top = 10.dp),
                verticalAlignment = Alignment.Top,
                horizontalArrangement = Arrangement.Center
            ) {
                groups.forEach { groupInfo ->
                    Button(
                        onClick = {
                            setSelectedGroup(groupInfo)
                                  },
                        modifier = Modifier.padding(2.dp),
                        shape = RoundedCornerShape(15.dp),
                        colors = ButtonDefaults.buttonColors(
                            backgroundColor = Color.Gray,
                            contentColor = Color.White
                        )
                    ) {
                        Text(text = groupInfo)
                    }
                }
            }
            val selectedGroupData = groupData.find { it.group == selectedGroup }
            selectedGroupData?.let {groupInfo ->
            // Group Table
            Text(
                text = "Group ${groupInfo.group}",
                color = Color.White,
                style = MaterialTheme.typography.h4,
                textAlign = TextAlign.Center
            )
            Surface(
                modifier = Modifier
                    .padding(7.dp)
                    .padding(top = 10.dp),
                color = Color.Gray,
                shape = RoundedCornerShape(10.dp),
                border = BorderStroke(2.dp, Color.Gray),
                elevation = 10.dp
            ) {
                    TeamTable(groupInfo.teams)
            }
            // Fields to fill the results
            Spacer(modifier = Modifier.height(16.dp))
            Text(
                text = "Enter the match results: ",
                color = Color.White,
                style = MaterialTheme.typography.h6
            )
            Spacer(modifier = Modifier.height(8.dp))

            Column(
                modifier = Modifier
                    .verticalScroll(rememberScrollState())
                    .padding(bottom = 30.dp)
            ) {
                for (i in 0 until groupInfo.teams.size - 1) {
                    for (j in i + 1 until groupInfo.teams.size) {
                        val teamA = groupInfo.teams[i]
                        val teamB = groupInfo.teams[j]
                        val result = matchResult[i * 2 + j - (i * 1)]

                        MatchResultInput(
                            teamA = teamA.shortName,
                            teamB = teamB.shortName,
                            matchResult = result,
                            onResultChanged = { newResult ->
                                val updatedMatchResult = matchResult.toMutableList()
                                updatedMatchResult[i * 2 + j - (i + 1)] = newResult
                                setMatchResult(updatedMatchResult)

                                if (newResult.scoreA > newResult.scoreB) {
                                    teamA.matchesPlayed++
                                    teamA.matchesWon++
                                    teamA.points += 3
                                    teamB.matchesPlayed++
                                    teamB.matchesLost++
                                } else if (newResult.scoreA < newResult.scoreB) {
                                    teamA.matchesPlayed++
                                    teamA.matchesLost++
                                    teamB.matchesPlayed++
                                    teamB.matchesWon++
                                    teamB.points += 3
                                } else {
                                    // It's a draw
                                    teamA.matchesPlayed++
                                    teamA.matchesDrawn++
                                    teamA.points++
                                    teamB.matchesPlayed++
                                    teamB.matchesDrawn++
                                    teamB.points++
                                }
                            })
                    }
                }
            }
            }
        }
    }
}
@Composable
fun MatchResultInput(
    teamA: String,
    teamB: String,
    matchResult: EuroMatchResult,
    onResultChanged: (EuroMatchResult) -> Unit) {

    val scoreA = remember { mutableStateOf(matchResult.scoreA.toString()) }
    val scoreB = remember { mutableStateOf(matchResult.scoreB.toString()) }
    val showPredictions = remember { mutableStateOf(false) }
    val buttonEnabled = remember { mutableStateOf(true) }


    Surface(
        modifier = Modifier
            .padding(start = 7.dp, end = 7.dp, top = 20.dp),
        color = Color.Gray,
        shape = RoundedCornerShape(topStart = 40.dp, topEnd = 40.dp), //30
        border = BorderStroke(3.dp, Color.White),
        elevation = 10.dp
    ) {
        Row(
            modifier = Modifier
                .fillMaxWidth()
                .padding(4.dp)
                .padding(start = 15.dp, end = 15.dp, bottom = 5.dp),
            horizontalArrangement = Arrangement.SpaceBetween,
            verticalAlignment = Alignment.CenterVertically
        ) {
            Column(
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally,
                modifier = Modifier.padding(end = 8.dp)
            ) {
                Image(
                    painterResource(id = R.drawable.flag_poland),
                    contentDescription = null,
                    modifier = Modifier.size(70.dp) //70
                )
                Text(
                    text = teamA,
                    fontSize = 19.sp
                )
            }
            ScoreInput(
                scoreState = scoreA,
                onAction = KeyboardActions { FocusRequester.Default.requestFocus() },
                enabled = true,
                onScoreChanged = {newScore ->
                    scoreA.value = newScore
                }
            )
            Column(
                verticalArrangement = Arrangement.SpaceBetween,
                horizontalAlignment = Alignment.CenterHorizontally,
            ) {
                Text(
                    text = ":",
                    modifier = Modifier.padding(top = 40.dp,bottom = 12.dp),
                    textAlign = TextAlign.Center)
                Button(
                    onClick = {
                              onResultChanged(EuroMatchResult(scoreA.value.toIntOrNull() ?: 0, scoreB.value.toIntOrNull() ?: 0))
                              showPredictions.value = true
                              buttonEnabled.value = false
                              },
                    modifier = Modifier.size(34.dp),
                    shape = CircleShape,
                    colors = ButtonDefaults.buttonColors(backgroundColor = green_check, contentColor = Color.White, disabledBackgroundColor = little_green_check),
                    enabled = buttonEnabled.value) {
                    Text(text = "✓", fontSize = 12.sp, textAlign = TextAlign.Center, fontWeight = FontWeight.Bold)
                }
            }

            ScoreInput(scoreState = scoreB,
                onScoreChanged = { newScore ->
                    scoreB.value = newScore
                })
            Column(
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally,
                modifier = Modifier.padding(start = 8.dp)
            ) {

                Image(
                    painterResource(id = R.drawable.flag_germany),
                    contentDescription = null,
                    modifier = Modifier.size(70.dp)
                )
                Text(
                    text = teamB,
                    fontSize = 19.sp
                )
            }
        }
    }
    Surface(modifier = Modifier.padding(start = 7.dp, end = 7.dp),
        color = Color.White,
        shape = RoundedCornerShape(bottomStart = 40.dp, bottomEnd = 40.dp), //30
        elevation = 10.dp) {
        Row(modifier = Modifier
            .fillMaxWidth()
            .padding(top = 5.dp, bottom = 5.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Center) {
        if (!showPredictions.value){
        Text(
            text = "Confirm the result to see other players predictions",
            modifier = Modifier.padding(7.dp),
            textAlign = TextAlign.Center)
        } else {

                Text(text = "33%", modifier = Modifier.weight(1f), textAlign = TextAlign.Center, fontSize = 20.sp, fontWeight = FontWeight.Bold)
                Text(text = "34%", modifier = Modifier.weight(1f), textAlign = TextAlign.Center, fontSize = 20.sp, fontWeight = FontWeight.Bold)
                Text(text = "33%", modifier = Modifier.weight(1f), textAlign = TextAlign.Center, fontSize = 20.sp, fontWeight = FontWeight.Bold)
            }
        }
    }
}
@Composable
fun TeamTable(teams: List<Team>) {
    val sortedTeams = teams.sortedByDescending { it.points }

    Column(modifier = Modifier.padding(3.dp)) {
        Row(
            modifier = Modifier.fillMaxWidth(),
            horizontalArrangement = Arrangement.SpaceBetween,
            verticalAlignment = Alignment.CenterVertically
        ) {
            val headerTitles = listOf("M", "W", "D", "L", "Pts")
            Text(
                "Country",
                fontWeight = FontWeight.Bold,
                textAlign = TextAlign.Center,
                modifier = Modifier.width(150.dp)
            )
            headerTitles.forEach { titles ->
                Text(
                    text = titles,
                    fontWeight = FontWeight.Bold,
                    textAlign = TextAlign.Center,
                    modifier = Modifier.width(50.dp)
                )
            }
        }

        sortedTeams.forEachIndexed { index, team ->
            Surface(color = Color.White) {
                Row(
                    modifier = Modifier.fillMaxWidth(),
                    horizontalArrangement = Arrangement.SpaceBetween,
                    verticalAlignment = Alignment.CenterVertically
                ) {
                    Image(
                        painterResource(id = R.drawable.flag_poland),
                        contentDescription = null,
                        modifier = Modifier.size(30.dp)
                    )
                    Text(
                        team.name,
                        textAlign = TextAlign.Start,
                        modifier = Modifier
                            .width(120.dp)
                            .padding(start = 10.dp)
                    )
                    listOf(
                        team.matchesPlayed,
                        team.matchesWon,
                        team.matchesDrawn,
                        team.matchesLost,
                        team.points).forEach { value ->
                        Text(
                            text = value.toString(),
                            textAlign = TextAlign.Center,
                            modifier = Modifier.width(50.dp)
                        )
                    }
                }
                Divider(thickness = 2.dp)
            }
        }
    }
}

data class EuroMatchResult(
    val scoreA: Int, val scoreB: Int
)

data class GroupData(
    val group: String,
    val teams: List<Team>
)

data class Team(
    val name: String,
    val shortName: String,
    var matchesPlayed: Int = 0,
    var matchesWon: Int = 0,
    var matchesDrawn: Int = 0,
    var matchesLost: Int = 0,
    var points: Int = 0,
)
android kotlin android-jetpack-compose textfield
1个回答
0
投票

(我希望我答对了你的问题。)

我猜您期望的行为是,当

matchResult
的值在
MatchResultInput
中更改时,您的文本字段将使用新值进行更新。然而,事实并非如此。
State
对象在重组过程中保持不变,无论触发它的是什么,包括可组合项参数的更改。

有 2 种方法可以更改文本输入

  1. “正确的”是不使用这两个状态对象。相反,只需将状态传递给

    MatchResultInput
    两个函数
    updateScoreA
    updateScoreB
    以及 hoist 到父组件即可。现在您可以直接使用
    matchResult
    的值作为文本输入的参数,并且每当父组件更新它时,您的文本输入也应该更新

  2. 更快的解决方案,只需添加一个依赖于

    matchResult.scoreA
    的 LaunchedEffect 即可在分数发生变化时更新分数 A 的状态,并为分数 B

    更新另一个状态
© www.soinside.com 2019 - 2024. All rights reserved.