AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / coding / 问题 / 79063853
Accepted
A. Cedano
A. Cedano
Asked: 2024-10-08 06:59:27 +0800 CST2024-10-08 06:59:27 +0800 CST 2024-10-08 06:59:27 +0800 CST

如何避免 Jetpack Compose 中 LazyVerticalGrid 中的复选框重复?

  • 772

我正在尝试创建一个 Bug 报告屏幕。用户必须输入 Bug 描述并可以选择各种复选框。然后我检索该信息并使用它编写电子邮件。

我的问题是,当在 TextField 中输入文本或者旋转屏幕时,复选框会重新创建。

为什么会发生这种情况?我该如何避免?

BugItems 是我在资源数组中采用的固定元素。我创建了两个数据类来表示 Bug 报告。

data class BugReport(
    val message: String,
    val bugItems: List<BugItem>,
)

data class BugItem(
    val title: String,
    val completed: Boolean = false,
)

这是屏幕的组合:

@ExperimentalFoundationApi
@Composable
fun BugReportScreen(
    modifier: Modifier = Modifier
) {
    val launcher = rememberLauncherForActivityResult(
        contract = ActivityResultContracts.StartActivityForResult(),
        onResult = { }
    )

    val message = remember { mutableStateOf("") }

    val bugItems = remember {
        mutableStateListOf<BugItem>()
    }

    stringArrayResource(id = R.array.bug_report).forEach {
        bugItems += BugItem(title = it, completed = false)
    }
    val bugReport = remember {
        mutableStateOf(BugReport(message.value, bugItems))
    }

    Box(
        modifier = modifier,
    ) {
        Column(
            modifier = modifier
                .fillMaxSize()
                .verticalScroll(rememberScrollState())
        ) {

            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(50.dp)
            )

            GenericToolbar(title = "Bug Report")
            Spacer(modifier = Modifier.weight(1f)) 
            Text(text = stringResource(id = R.string.bug_intro))
            Text(text = stringResource(id = R.string.bug_description))

            TextFieldBugDescription(message)
            Text(text = stringResource(id = R.string.bug_check))    
            
            LazyVerticalGrid(
                modifier = Modifier.heightIn(max = 1000.dp),
                columns = GridCells.Fixed(2),
                content = {
                    items(bugReport.value.bugItems.size) { index ->
                        Row(
                            modifier = Modifier.padding(1.dp),
                            verticalAlignment = Alignment.CenterVertically
                        ) {

                            Checkbox(
                                checked = bugItems[index].completed,
                                onCheckedChange = { checked ->
                                    bugItems[index] = bugItems[index].copy(completed = checked)
                                }
                            )
                            Text(
                                text = bugItems[index].title,
                                style = MaterialTheme.typography.bodyLarge,
                            )
                        }
                    }

                }

            )
            Text(text = stringResource(id = R.string.bug_send))
            Row(
                horizontalArrangement = Arrangement.Center,
                modifier = Modifier.fillMaxWidth(),
            ) {
                LPlusButton(
                    onClick = {
                        sendEmail(launcher, bugReport)
                    },
                    text = { Text(text = stringResource(R.string.send_email)) },
                    leadingIcon = {
                        Icon(
                            imageVector = LPlusIcons.Email,
                            contentDescription = stringResource(R.string.send_email)
                        )
                    },
                    modifier = Modifier
                        .padding(horizontal = 24.dp)
                        .widthIn(364.dp)
                        .fillMaxWidth(),
                )
            }
        }
    }
}

@Composable
fun TextFieldBugDescription(message: MutableState<String>) {
    TextField(
        value = message.value,
        onValueChange = { message.value = it },
        label = { Text(stringResource(id = R.string.bug_label)) },
        maxLines = 2,
        modifier = Modifier
            .padding(20.dp)
            .fillMaxWidth()
            .height(200.dp)
    )
}

正如您在第一个屏幕截图中看到的,复选框是正确的:

在此处输入图片描述

但是当我激活 TextField 并输入一些文本时,元素会被重新创建。如果我旋转屏幕,也会发生同样的事情:

在此处输入图片描述

  • 2 2 个回答
  • 46 Views

2 个回答

  • Voted
  1. Best Answer
    BenjyTec
    2024-10-08T15:46:34+08:002024-10-08T15:46:34+08:00

    您的代码中存在几个问题:

    • stringArrayResource每次父 Composable 重组时都会执行,这会一直向列表中添加越来越BugItem多bugItems的
    • 您bugReport用进行初始化message.value,但是在发生变化时不会更新它message。
    • 您正在将 传递MutableState<String>给您的TextFieldBugDescriptionComposable,这是不推荐的。

    旋转设备时,所有状态都可能会丢失。为了防止这种情况发生,请使用或rememberSaveable等类型,或者将所有应在配置更改后继续存在的变量委托给 ,并使用 公开它们,并使用 在 Composable 中观察它们。StringIntViewModelFlowcollectAsStateWithLifecycle

    就你的情况而言,由于你想存储和修改 本身不支持的 bugItems 列表rememberSaveable,我建议引入一个ViewModel类。就你的情况而言,你甚至可以使用AndroidViewModel直接BugItem用String数组初始化列表:

    class BugViewModel(application: Application) : AndroidViewModel(application) {
    
        // this is the internal modifyable variable
        private val _bugItems = MutableStateFlow<List<BugItem>>(emptyList())
        // this is the public readonly variable to be exposed to the Composable
        val bugItems: StateFlow<List<BugItem>> get() = _bugItems
    
        init {
            val bugsArray = application.resources.getStringArray(R.array.my_bugs)
            val initialBugItems = bugsArray.map { BugItem(title = it) }
            _bugItems.value = initialBugItems
        }
    
        fun updateBugItem(updatedItem: BugItem, newCompleted: Boolean) {
            val updatedList = _bugItems.value.map { item ->
                if (item.title == updatedItem.title) item.copy(completed = newCompleted) else item
            }
            _bugItems.value = updatedList
        }
    }
    

    然后,获取ViewModel使用该viewModel()函数并在 Composable 中观察它,如下所示:

    fun BugReportScreen(
        modifier: Modifier = Modifier,
        bugViewModel: BugViewModel = viewModel()
    ) {
    
        //...
        val bugItems by bugViewModel.bugItems.collectAsStateWithLifecycle()
    
        //...
        Checkbox(
            checked = bugItems[index].completed,
            onCheckedChange = { checked ->
                bugViewModel.updateBugItem(bugItems[index], checked)
            }
        )
    }
    

    bugReport然后,只需在提交时组装:

    onClick = {
        sendEmail(launcher, BugReport(message.value, bugItems))
    },
    

    最后,将您TextFieldBugDescription的

    @Composable
    fun TextFieldBugDescription(message: String, onMessageChanged: (String) -> Unit) {
        TextField(
            value = message.value,
            onValueChange = onMessageChanged,
            label = { Text(stringResource(id = R.string.bug_label)) },
            maxLines = 2,
            modifier = Modifier
                .padding(20.dp)
                .fillMaxWidth()
                .height(200.dp)
        )
    }
    

    并将其称为

    TextFieldBugDescription(
        message = message.value,
        onMessageChanged = { newMessage ->
            message.value = newMessage
        }
    )
    
    • 3
  2. Siva Nimmala
    2024-10-08T12:33:32+08:002024-10-08T12:33:32+08:00

    在 LazyVerticalGrid 内容项()中使用键参数并分配键 id,以便组合将显示唯一键项。

    LazyVerticalGrid(
                modifier = Modifier.heightIn(max = 1000.dp),
                columns = GridCells.Fixed(2),
                content = {
                    items(key = specificId, count = bugReport.value.bugItems.size) { index ->
                        Row(
                            modifier = Modifier.padding(1.dp),
                            verticalAlignment = Alignment.CenterVertically
                        ) {
    
                            Checkbox(
                                checked = bugItems[index].completed,
                                onCheckedChange = { checked ->
                                    bugItems[index] = bugItems[index].copy(completed = checked)
                                }
                            )
                            Text(
                                text = bugItems[index].title,
                                style = MaterialTheme.typography.bodyLarge,
                            )
                        }
                    }
    
                }
    
            )
    
    • 0

相关问题

  • 将复制活动的序列号添加到 Blob

  • Packer 动态源重复工件

  • 选择每组连续 1 的行

  • 图形 API 调用列表 subscribedSkus 状态权限不足,但已授予权限

  • 根据列值创建单独的 DF 的函数

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    Vue 3:创建时出错“预期标识符但发现‘导入’”[重复]

    • 1 个回答
  • Marko Smith

    为什么这个简单而小的 Java 代码在所有 Graal JVM 上的运行速度都快 30 倍,但在任何 Oracle JVM 上却不行?

    • 1 个回答
  • Marko Smith

    具有指定基础类型但没有枚举器的“枚举类”的用途是什么?

    • 1 个回答
  • Marko Smith

    如何修复未手动导入的模块的 MODULE_NOT_FOUND 错误?

    • 6 个回答
  • Marko Smith

    `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它?

    • 3 个回答
  • Marko Smith

    何时应使用 std::inplace_vector 而不是 std::vector?

    • 3 个回答
  • Marko Smith

    在 C++ 中,一个不执行任何操作的空程序需要 204KB 的堆,但在 C 中则不需要

    • 1 个回答
  • Marko Smith

    PowerBI 目前与 BigQuery 不兼容:Simba 驱动程序与 Windows 更新有关

    • 2 个回答
  • Marko Smith

    AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String”

    • 1 个回答
  • Marko Smith

    我正在尝试仅使用海龟随机和数学模块来制作吃豆人游戏

    • 1 个回答
  • Martin Hope
    Aleksandr Dubinsky 为什么 InetAddress 上的 switch 模式匹配会失败,并出现“未涵盖所有可能的输入值”? 2024-12-23 06:56:21 +0800 CST
  • Martin Hope
    Phillip Borge 为什么这个简单而小的 Java 代码在所有 Graal JVM 上的运行速度都快 30 倍,但在任何 Oracle JVM 上却不行? 2024-12-12 20:46:46 +0800 CST
  • Martin Hope
    Oodini 具有指定基础类型但没有枚举器的“枚举类”的用途是什么? 2024-12-12 06:27:11 +0800 CST
  • Martin Hope
    sleeptightAnsiC `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它? 2024-11-09 07:18:53 +0800 CST
  • Martin Hope
    The Mad Gamer 何时应使用 std::inplace_vector 而不是 std::vector? 2024-10-29 23:01:00 +0800 CST
  • Martin Hope
    Chad Feller 在 5.2 版中,bash 条件语句中的 [[ .. ]] 中的分号现在是可选的吗? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench 为什么双破折号 (--) 会导致此 MariaDB 子句评估为 true? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng 为什么 `dict(id=1, **{'id': 2})` 有时会引发 `KeyError: 'id'` 而不是 TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String” 2024-03-20 03:12:31 +0800 CST
  • Martin Hope
    MarkB 为什么 GCC 生成有条件执行 SIMD 实现的代码? 2024-02-17 06:17:14 +0800 CST

热门标签

python javascript c++ c# java typescript sql reactjs html

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve