Jetpack Compose下拉菜单无法显示已添加用户名列表的问题
Jetpack Compose下拉菜单不显示用户名问题修复
问题:注册页面输入用户名并保存后,Logcat显示ViewModel中的列表长度已更新,但首页点击菜单按钮后,下拉菜单里看不到任何用户名,调用列表时长度显示为0。
问题根源
- ViewModel实例不共享:注册页和首页通过
viewModel()获取的ViewModel可能属于不同的ViewModelStoreOwner(比如导航栈不同),导致首页拿到的是全新的空列表实例。 - 状态未被Compose感知:当前ViewModel返回的是普通List,Compose无法监听列表的更新,即使列表内容变化,UI也不会自动重组刷新。
修复步骤
1. 重构ViewModel,正确暴露可观察状态
将内部的可变状态列表通过可观察的方式对外暴露,让Compose能感知变化:
data class UserNameUiState( val userName: String ) class DropDownMenuViewModel: ViewModel() { // 内部维护的可变状态列表 private val _userNames = mutableStateListOf<UserNameUiState>() // 对外暴露不可变的可观察列表,Compose能监听其变化 val userNames: List<UserNameUiState> get() = _userNames // 添加用户名到列表 fun addUserName(name: UserNameUiState) { _userNames.add(name) } }
2. 确保ViewModel全局共享
在获取ViewModel时,指定使用Activity级别的ViewModelStoreOwner,保证注册页和首页使用同一个ViewModel实例:
- 注册页修改:
@Composable fun UserSignUpScreenInfo( username: String, navController: NavController, dropDownMenuViewModel: DropDownMenuViewModel = viewModel( viewModelStoreOwner = LocalViewModelStoreOwner.current!! ) ) { // 原有输入逻辑不变,仅ViewModel获取方式修改 val textFieldUserName = rememberSaveable { mutableStateOf(username) } Column(/* 原有布局代码 */) { // 原有TextField、按钮逻辑不变 Button( onClick = { if(textFieldUserName.value.isNotEmpty()) { dropDownMenuViewModel.addUserName( UserNameUiState(userName = textFieldUserName.value) ) } navController.navigate(DestinationScreens.HomePage.route) } ) { Text(text = "Next") } } }
- 首页修改:
@Composable fun HomePageTopAppBar( modifier: Modifier = Modifier, dropDownMenuViewModel: DropDownMenuViewModel = viewModel( viewModelStoreOwner = LocalViewModelStoreOwner.current!! ) ) { var expandedMenu by remember { mutableStateOf(false) } // 直接使用ViewModel暴露的可观察列表 val listItems = dropDownMenuViewModel.userNames Row(modifier = modifier.fillMaxWidth().background(Color.LightGray)) { IconButton(onClick = { expandedMenu = true }) { Icon(Icons.Filled.Menu, "Menu Button", tint = Color.DarkGray) } DropdownMenu( expanded = expandedMenu, onDismissRequest = { expandedMenu = false }, ) { // 列表变化时自动重组UI listItems.forEach { user -> DropdownMenuItem(onClick = { /*TODO*/ }) { Icon(Icons.Filled.AccountCircle, "Account", tint = Color.DarkGray) Text(text = user.userName, modifier = Modifier.padding(start = 4.dp), color = Color.DarkGray) } } } Text(text = "App", textAlign = TextAlign.Center, color = Color.Red) } Divider(color = Color.DarkGray, modifier = Modifier.fillMaxWidth().width(1.dp)) }
3. 额外优化:保存输入状态
注册页的TextField状态改用rememberSaveable,避免屏幕旋转时丢失输入内容:
val textFieldUserName = rememberSaveable { mutableStateOf(username) }
内容的提问来源于stack exchange,提问作者TurboScript
相关产品推荐
相关产品推荐

