保留 ViewModel 的数据

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

目前,我有两个视图组件: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)
        }
    }
}
android kotlin android-jetpack-compose viewmodel compose-recomposition
1个回答
0
投票

据我所知,您正在 CharacterSkillScreen 和 ItemSkillView 中创建 SkillViewModel 的单独实例。每次创建 ItemSkillView 时,都会创建一个新的 ViewModel。为了解决这个问题,你可以将ViewModel传递到CharacterSkillScreen中,然后传递到你自己的ItemSkillView中,如下所示:

ItemSkillView(
    skillModel = skillModel,
    statsValue = statsFieldValue,
    skillViewModel = skillViewModel
)
© www.soinside.com 2019 - 2024. All rights reserved.