目前,我有两个视图组件:CharacterScreen 和CharacterSkillScreen。我可以从CharacterScreen导航到CharacterSkillScreen。
在CharacterSkillScreen视图上,顾名思义,我可以添加技能(ItemSkillView)。此级别的功能没有问题。
当由于某种原因,我想通过单击键盘的后退按钮返回到上一个视图,然后决定返回到CharacterSkillScreen时,就会出现问题。不幸的是,任何可能的附加技能都消失了。页面已返回0。
我尝试了很多事情,但没有真正理解我在做什么(使用序列化将技能列表作为导航参数传递(我没有明白),使用 Bundle 而不是序列化......)
迄今为止的最新测试:rememberSaveable。正如你可以想象的那样,没有任何变化。问题依然存在。
我向您提供代码希望您能帮助我。
代码:
class SkillViewModel() : ViewModel() {
private val _uiState = MutableStateFlow(SkillUiState())
val uiState: StateFlow<SkillUiState> = _uiState.asStateFlow()
// Mise à jour de l'état de l'interface utilisateur : Compétences
private fun updateSkillState(update: (SkillUiState) -> SkillUiState) {
_uiState.value = update(_uiState.value)
}
fun updateSkillTitle(id: String, text: String) {
updateSkillState { state ->
val updateSkillItem = state.skillItem.map {
if (it.id == id) {
it.copy(title = text)
} else {
it
}
}
state.copy(skillItem = updateSkillItem)
}
}
fun updateSkillDescribe(id: String, describe: String) {
updateSkillState { state ->
val updatedSkillItem = state.skillItem.map {
if (it.id == id) {
it.copy(describe = describe)
} else {
it
}
}
state.copy(skillItem = updatedSkillItem)
}
}
fun updateFirstCaracSelected(id: String, firstCarac: String) {
updateSkillState { state ->
val updatedSkillItem = state.skillItem.map {
if (it.id == id) {
it.copy(firstCarac = firstCarac)
} else {
it
}
}
state.copy(skillItem = updatedSkillItem)
}
}
fun updateSecondCaracSelected(id: String, secondCarac: String) {
updateSkillState { state ->
val updatedSkillItem = state.skillItem.map {
if (it.id == id) {
it.copy(secondCarac = secondCarac)
} else {
it
}
}
state.copy(skillItem = updatedSkillItem)
}
}
fun updateFirstParticularity(id: String, firstParticularity: String) {
updateSkillState { state ->
val updatedSkillItem = state.skillItem.map {
if (it.id == id) {
it.copy(firstParticularity = firstParticularity)
} else {
it
}
}
state.copy(skillItem = updatedSkillItem)
}
}
fun updateSecondParticularity(id: String, secondParticularity: String) {
updateSkillState { state ->
val updatedSkillItem = state.skillItem.map {
if (it.id == id) {
it.copy(secondParticularity = secondParticularity)
} else {
it
}
}
state.copy(skillItem = updatedSkillItem)
}
}
//Ajouter une compétence
fun addSkillItem() {
val id = UUID.randomUUID().toString()
val newSkill = SkillModel(
id,
"",
"",
"",
"",
"",
"")
updateSkillState { state ->
state.copy(skillItem = (state.skillItem + newSkill))
}
}
//Calcul des points de compétences
fun skillPointCalculated(firstCarac: String, secondCarac: String) : String {
val points = "${(firstCarac.toIntOrNull() ?: 0) + (secondCarac.toIntOrNull() ?: 0)}"
updateSkillState { it.copy(skillPoints = points) }
return points
}
}
@Composable
fun CharacterSkillScreen(
arguments: Bundle? = null,
skillViewModel: SkillViewModel = viewModel()
) {
val rememberSkillList = rememberSaveable {
mutableStateOf(emptyList<SkillModel>())
}
val skillUiState by skillViewModel.uiState.collectAsState()
LaunchedEffect(key1 = skillUiState.skillItem) {
rememberSkillList.value = skillUiState.skillItem
}
Column {
val strengthValue = arguments?.getInt("strenght") ?: 0
val dexterityValue = arguments?.getInt("dexterity") ?: 0
val constituionValue = arguments?.getInt("constitution") ?: 0
val intelligenceValue = arguments?.getInt("intelligence") ?: 0
val wisdomValue = arguments?.getInt("wisdom") ?: 0
val charismValue = arguments?.getInt("charism") ?: 0
val statsFieldValue = mapOf(
"FOR" to strengthValue,
"DEX" to dexterityValue,
"CON" to constituionValue,
"INT" to intelligenceValue,
"SAG" to wisdomValue,
"CHA" to charismValue
)
Row(modifier = Modifier.padding(20.dp)) {
statsFieldValue.forEach { (label, value) ->
StatsField(
label = label,
value = value.toString(),
onValueChange = { },
modifier = Modifier.weight(1f)
)
}
}
Column(
modifier = Modifier
.verticalScroll(rememberScrollState())
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
){
rememberSkillList.value.forEach{ skillModel ->
ItemSkillView(
skillModel = skillModel,
statsValue = statsFieldValue)
}
Log.d("Skills", "${rememberSkillList.value}")
Divider(thickness = 1.dp)
Button(
onClick = {
skillViewModel.addSkillItem()
},
modifier = Modifier.padding(top = 10.dp)
) {
Text(text = "Ajouter une compétence")
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ItemSkillView(
skillModel: SkillModel,
statsValue: Map<String, Int>,
skillViewModel: SkillViewModel = viewModel()
) {
var isExpanded by remember { mutableStateOf(false) }
val firstCarac = skillModel.firstCarac
val secondCarac = skillModel.secondCarac
val firstCaracValue = statsValue[firstCarac].toString()
val secondCaracValue = statsValue[secondCarac].toString()
val skillPoint = skillViewModel.skillPointCalculated(firstCaracValue, secondCaracValue)
Column(
modifier = Modifier
.fillMaxWidth()
.clickable { isExpanded = !isExpanded }
.animateContentSize()
) {
ConstraintLayout(modifier = Modifier.fillMaxWidth()) {
val (icon, skill, resultSkill) = createRefs()
Icon(
painter = painterResource(id = R.drawable.expand_more),
contentDescription = "Expanded button",
tint = Color.Black,
modifier = Modifier
.size(40.dp)
.constrainAs(icon) {
start.linkTo(parent.start, margin = 10.dp)
top.linkTo(skill.top)
bottom.linkTo(skill.bottom)
}
)
val title = skillModel.title
TextField(
value = title,
onValueChange = {
skillViewModel.updateSkillTitle(skillModel.id, it)
},
label = { Text(text = "NOM DE LA COMPÉTENCE ") },
colors = TextFieldDefaults.outlinedTextFieldColors(
focusedBorderColor = Color.Transparent,
unfocusedBorderColor = Color.Transparent
),
modifier = Modifier.constrainAs(skill) {
start.linkTo(icon.end)
end.linkTo(resultSkill.start)
}
)
Text(
text = skillPoint,
fontSize = 16.sp,
textAlign = TextAlign.Center,
modifier = Modifier
.border(1.dp, Color.Black)
.padding(top = 3.dp, bottom = 3.dp)
.constrainAs(resultSkill) {
start.linkTo(skill.end, margin = 18.dp)
end.linkTo(parent.end, margin = 18.dp)
top.linkTo(skill.top)
bottom.linkTo(skill.bottom)
width = Dimension.fillToConstraints
}
)
Divider(thickness = 1.dp)
}
if(isExpanded) {
ExposedDropDownMenuSkill(skillModel = skillModel)
}
}
}
据我所知,您正在 CharacterSkillScreen 和 ItemSkillView 中创建 SkillViewModel 的单独实例。每次创建 ItemSkillView 时,都会创建一个新的 ViewModel。为了解决这个问题,你可以将ViewModel传递到CharacterSkillScreen中,然后传递到你自己的ItemSkillView中,如下所示:
ItemSkillView(
skillModel = skillModel,
statsValue = statsFieldValue,
skillViewModel = skillViewModel
)