You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose中如何为每个赛事匹配添加用户预测结果?

问题描述

我用LazyColumn展示从API获取的足球赛事Match列表:

LazyColumn {
    items(state.matches) { match->
        MatchItem(
            match = match,
            vm = vm
        )
    }
}

需求是让用户对每场比赛进行结果预测,ResultText组件代码如下:

@Composable
fun ResultText(
    showText: Boolean,
    result: ResultState,
    onResultChanged: (Int) -> Unit
) {
    if (showText) {
        Text(text = result, fontSize = MaterialTheme.typography.body2.fontSize)
    } else {
        ResultPicker(onResultChanged = onResultChanged)
    }
}

但预测数据ResultState与赛事数据分离,无法为每场比赛绑定对应的预测结果。补充的MatchItem、ResultState和ViewModel代码如下:

MatchItem组件:

@Composable
fun MatchItem(
    match: Match,
    result: ResultState,
    vm: HomeViewModel
) {
    Column(
        modifier = Modifier
            .fillMaxHeight()
            .fillMaxWidth()
            .padding(12.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.SpaceAround
    ) {
        TeamInfo(
            team = match.team1,
            painter = flag1,
            horizontal = Alignment.CenterHorizontally,
            vertical = Arrangement.Top
        )

        ResultText(
            showText = (textOrPicker == ShowTextOrPicker.TEXT),
            result = result.team1,
            onResultChanged = {
                vm.changeResult(result = ResultState(
                    team1 = it.toString(),
                    team2 = result.team2
                ))
            }
        )

        Text(
            modifier = Modifier.padding(vertical = 10.dp),
            text = "VS",
            textAlign = TextAlign.Center,
            fontSize = 20.sp
        )

        TeamInfo(
            team = match.team2,
            painter = flag2,
            horizontal = Alignment.CenterHorizontally,
            vertical = Arrangement.Bottom
        )

        ResultText(
            showText = (textOrPicker == ShowTextOrPicker.TEXT),
            result = result.team2,
            onResultChanged = {
                vm.changeResult(result = ResultState(
                    team1 = result.team2,
                    team2 = it.toString()
                ))
            }
        )
    }
}

ResultState数据类:

data class ResultState(
    val team1: String = "-",
    val team2: String = "-"
)

ViewModel代码:

private val _resultState = mutableStateOf<List<ResultState>>(emptyList())
val resultState = _resultState
解决方案

核心思路是通过赛事的唯一ID建立Match和ResultState的关联,用Map存储预测结果,精准匹配每场比赛的预测数据。

1. 确保Match类包含唯一标识

确认你的Match类有唯一ID字段(比如id: String),如果没有,先添加该字段,这是关联的基础。

2. 修改ViewModel的状态存储

把原来的List<ResultState>改成Map<String, ResultState>,键为Match的ID,值为对应预测结果:

private val _resultState = mutableStateOf<Map<String, ResultState>>(emptyMap())
val resultState: State<Map<String, ResultState>> = _resultState

// 获取到赛事列表后,初始化默认预测结果
fun initResultStates(matches: List<Match>) {
    val defaultResults = matches.associate { match ->
        match.id to ResultState() // 用默认值"-"初始化
    }
    _resultState.value = defaultResults
}

// 更新指定比赛的预测结果
fun updateMatchResult(matchId: String, newResult: ResultState) {
    _resultState.value = _resultState.value.toMutableMap().apply {
        put(matchId, newResult)
    }
}

3. 在LazyColumn中传递对应ResultState

渲染MatchItem时,通过Match的ID从Map中获取对应预测结果:

LazyColumn {
    items(state.matches) { match ->
        val result = vm.resultState.value[match.id] ?: ResultState()
        MatchItem(
            match = match,
            result = result,
            vm = vm
        )
    }
}

注意:获取到matches数据后,调用vm.initResultStates(state.matches)完成预测结果Map的初始化。

4. 修改MatchItem的回调逻辑

更新MatchItem中的ResultText回调,调用ViewModel的updateMatchResult方法并传入当前Match的ID:

@Composable
fun MatchItem(
    match: Match,
    result: ResultState,
    vm: HomeViewModel
) {
    // ... 其他代码保持不变 ...

    ResultText(
        showText = (textOrPicker == ShowTextOrPicker.TEXT),
        result = result.team1,
        onResultChanged = { newTeam1Score ->
            val updatedResult = result.copy(team1 = newTeam1Score.toString())
            vm.updateMatchResult(match.id, updatedResult)
        }
    )

    // ... VS文本区域 ...

    ResultText(
        showText = (textOrPicker == ShowTextOrPicker.TEXT),
        result = result.team2,
        onResultChanged = { newTeam2Score ->
            val updatedResult = result.copy(team2 = newTeam2Score.toString())
            vm.updateMatchResult(match.id, updatedResult)
        }
    )
}

5. 修正ResultText组件的参数错误

原ResultText组件中result参数类型与Text组件需求不匹配,修正参数类型为String:

@Composable
fun ResultText(
    showText: Boolean,
    result: String, // 改为String类型
    onResultChanged: (Int) -> Unit
) {
    if (showText) {
        Text(text = result, fontSize = MaterialTheme.typography.body2.fontSize)
    } else {
        ResultPicker(onResultChanged = onResultChanged)
    }
}

这样即可实现每场比赛与对应预测结果的绑定,用户修改某场比赛的预测时,只会更新该场的ResultState,不会影响其他比赛。


内容的提问来源于stack exchange,提问作者Roony

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 10:33:20