Jetpack Compose求助:点击子Composable时变更父组件变量状态
解决方案
方案一:ViewModel中维护每行独立的展开状态
你之前用ViewModel导致所有行展开,核心问题是用了单个Boolean变量管理全局状态,改成按行ID记录展开状态就能解决:
- 在ViewModel里定义状态存储当前展开的行ID(用
null表示无展开行):
class YourViewModel : ViewModel() { private val _expandedRowId = mutableStateOf<String?>(null) val expandedRowId: State<String?> = _expandedRowId fun toggleRowExpansion(rowId: String) { _expandedRowId.value = if (_expandedRowId.value == rowId) null else rowId } fun closeExpandedRow() { _expandedRowId.value = null } }
- 在每行组件中,通过行ID匹配控制DropdownMenu显示:
@Composable fun RowItem(rowId: String, viewModel: YourViewModel) { val expandedRowId by viewModel.expandedRowId val isExpanded = expandedRowId == rowId Row { // 行内其他内容 IconButton(onClick = { viewModel.toggleRowExpansion(rowId) }) { Icon(Icons.Default.MoreVert, contentDescription = "More") } DropdownMenu( expanded = isExpanded, onDismissRequest = { viewModel.closeExpandedRow() } ) { DropdownMenuItem(onClick = { // 执行Composable1的业务逻辑 viewModel.closeExpandedRow() // 点击后关闭菜单 }) { Text("Composable1") } // Composable2-Composable4同理,点击时调用closeExpandedRow() } } }
这样点击某一行的More图标时,只会展开当前行的菜单;点击菜单项后调用closeExpandedRow()即可关闭菜单。
方案二:将状态放在行组件内部(无需ViewModel)
如果状态不需要跨组件共享,直接用remember在每行内部维护独立状态更简单:
@Composable fun RowItem() { var showMore by remember { mutableStateOf(false) } Row { // 行内其他内容 IconButton(onClick = { showMore = !showMore }) { Icon(Icons.Default.MoreVert, contentDescription = "More") } DropdownMenu( expanded = showMore, onDismissRequest = { showMore = false } ) { DropdownMenuItem(onClick = { // 执行Composable1的业务逻辑 showMore = false // 点击后直接关闭当前菜单 }) { Text("Composable1") } // Composable2-Composable4同样在onClick里设置showMore = false } } }
这种方式下每行的showMore状态完全独立,不会出现全局展开的问题,点击菜单项时直接修改本地状态即可关闭菜单。
关于SideEffect/LaunchedEffect的问题
这两个API是处理Compose生命周期副作用的,本来就不适合直接修改组件内部状态,上面的两种方案已经完全覆盖你的需求,不需要用它们来解决。
内容的提问来源于stack exchange,提问作者Antonio Caravaggio
相关产品推荐
相关产品推荐

