You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose中能否为ExposedDropdownMenu实现分页加载?

为ExposedDropdownMenu实现分页加载功能

我需要给基于API数据的ExposedDropdownMenu添加分页功能,目前用普通List展示选项,想替换成ViewModel中的LazyPagingItems<Division>来实现分页加载。

修改后的DivisionDropDown组件

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DivisionDropDown(
    divisionPagingItems: LazyPagingItems<Division>,
    selectedItem: String,
    itemSelectListener: (String) -> Unit,
    modifier: Modifier = Modifier
) {
    var expanded by remember { mutableStateOf(false) }

    ExposedDropdownMenuBox(
        expanded = expanded,
        onExpandedChange = { expanded = !expanded },
        modifier = modifier.wrapContentWidth()
    ) {
        OutlinedTextField(
            value = selectedItem,
            shape = RoundedCornerShape(12.dp),
            label = { Text(stringResource(id = R.string.division_of_school)) },
            readOnly = true,
            onValueChange = {}, // 只读状态无需处理输入
            trailingIcon = {
                Icon(
                    painter = painterResource(R.drawable.ic_down),
                    contentDescription = "下拉菜单图标",
                    modifier = Modifier.rotate(if (expanded) 180f else 0f)
                )
            },
            maxLines = 1,
            modifier = Modifier
                .fillMaxWidth()
                .wrapContentHeight()
                .menuAnchor()
        )

        ExposedDropdownMenu(
            expanded = expanded,
            onDismissRequest = { expanded = false },
            modifier = Modifier
                .exposedDropdownSize(true)
                .heightIn(max = 300.dp) // 限制菜单最大高度,避免占满屏幕
        ) {
            LazyColumn {
                items(divisionPagingItems) { division ->
                    division?.let {
                        DropdownMenuItem(
                            text = { Text(it.name) }, // 假设Division类包含name字段
                            onClick = {
                                itemSelectListener(it.name)
                                expanded = false
                            },
                            contentPadding = ExposedDropdownMenuDefaults.ItemContentPadding,
                        )
                    }
                }

                // 处理分页加载状态
                divisionPagingItems.apply {
                    when {
                        loadState.refresh is LoadState.Loading -> {
                            item {
                                Box(modifier = Modifier.fillMaxWidth().padding(16.dp)) {
                                    CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
                                }
                            }
                        }
                        loadState.append is LoadState.Loading -> {
                            item {
                                Box(modifier = Modifier.fillMaxWidth().padding(16.dp)) {
                                    CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
                                }
                            }
                        }
                        loadState.append is LoadState.Error -> {
                            val error = divisionPagingItems.loadState.append as LoadState.Error
                            item {
                                Text(
                                    text = "加载失败:${error.error.message}",
                                    modifier = Modifier.fillMaxWidth().padding(16.dp),
                                    textAlign = TextAlign.Center,
                                    color = Color.Red
                                )
                            }
                        }
                    }
                }
            }
        }
    }
}

界面层调用代码修改

@Composable
fun SchoolInfoScreen(
    viewModel: ProfileEditViewModel
) {
    val divisionPagingItems: LazyPagingItems<Division> = viewModel.divisionState.collectAsLazyPagingItems()
    var selectedDivision by remember { mutableStateOf("") } // 根据业务逻辑初始化选中项

    ConstraintLayout(
        Modifier
            .fillMaxWidth()
            .fillMaxHeight()
            .padding(horizontal = 16.dp)
    ) {
        val (divisionDropDown) = createRefs()

        DivisionDropDown(
            divisionPagingItems = divisionPagingItems,
            selectedItem = selectedDivision,
            itemSelectListener = { selectedDivision = it },
            modifier = Modifier
                .constrainAs(divisionDropDown) {
                    top.linkTo(parent.top, 32.dp)
                    start.linkTo(parent.start)
                    end.linkTo(parent.end)
                }
        )
    }
}

关键实现要点

  • 替换列表容器:将原来的list.forEach替换为LazyColumn,配合items(divisionPagingItems)渲染分页数据,LazyColumn滚动到底部时会自动触发Paging3的下一页数据请求。
  • 参数适配:把组件的list: List<String>参数改为divisionPagingItems: LazyPagingItems<Division>,直接接收分页数据源。
  • 状态反馈:添加分页加载的状态UI,包括刷新加载、追加加载、加载错误的提示,优化用户体验。
  • 只读输入处理:只读状态下的OutlinedTextField无需处理onValueChange逻辑,直接留空即可。
  • 菜单高度限制:给ExposedDropdownMenu设置最大高度,避免下拉菜单过长影响界面布局。

内容的提问来源于stack exchange,提问作者Aminul Haque Aome

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 20:05:31