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

