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

Compose Multiplatform Android端ExposedDropdownMenu选项无法点击问题求助

Compose Multiplatform Android端ExposedDropdownMenu无法点击选项问题

问题现象

桌面端下拉菜单运行正常;Android端(模拟器及多款真机测试)可展开ExposedDropdownMenu查看选项,但无法点击/选中选项,仅能正常收起菜单。

临时可用的替代操作:

  • 为Android设备连接键盘,通过方向键导航至目标选项后按回车选中;
  • 点击按钮跳转至其他页面,再返回包含下拉菜单的原页面。

相关环境信息

  • 使用Voyager进行页面导航;
  • 所有依赖已更新至最新版本。

下拉菜单实现代码

@OptIn(ExperimentalMaterialApi::class)
@Composable
fun CustomExposedDropDown(
    label: @Composable BoxScope.() -> Unit,
    items: List<@Composable RowScope.() -> Unit>,
    onChange: (Int) -> Unit,
    modifier: Modifier = Modifier
) {
    var isExpanded by remember { mutableStateOf(false) }
    val iconRotation by animateFloatAsState(if (isExpanded) 180f else 0f)

    ExposedDropdownMenuBox(
        expanded = isExpanded,
        modifier = modifier,
        onExpandedChange = {
            isExpanded = it
        }
    ) {
        Box(
            contentAlignment = Alignment.Center,
            modifier = Modifier
                .fillMaxWidth()
                .heightIn(min = 36.dp)
                .background(
                    color = MaterialTheme.colors.onSurface
                        .copy(alpha = TextFieldDefaults.BackgroundOpacity),
                    shape = RoundedCornerShape(10.dp)
                )
                .clickable(onClick = {})
        ) {
            label()
            Icon(
                imageVector = Icons.Filled.ArrowDropDown,
                contentDescription = "Dropdown",
                tint = MaterialTheme.colors.primary,
                modifier = Modifier
                    .align(Alignment.CenterEnd)
                    .padding(end = 12.dp)
                    .size(12.dp)
                    .rotate(iconRotation)
            )
        }
        ExposedDropdownMenu(
            expanded = isExpanded,
            onDismissRequest = { isExpanded = false },
        ) {
            items.forEachIndexed { i, item ->
                DropdownMenuItem(
                    content = item,
                    onClick = {
                        onChange(i)
                        isExpanded = false
                    }
                )
            }
        }
    }
}

@OptIn(ExperimentalMaterialApi::class)
@Composable
fun DynamicSelectTextField(
    selectedValue: String,
    options: List<String>,
    label: String,
    onValueChangedEvent: (String) -> Unit,
    modifier: Modifier = Modifier
) {
    var expanded by remember { mutableStateOf(false) }

    ExposedDropdownMenuBox(
        expanded = expanded,
        onExpandedChange = { expanded = !expanded },
        modifier = modifier
    ) {
        OutlinedTextField(
            readOnly = true,
            value = selectedValue,
            onValueChange = {},
            label = { Text(text = label) },
            trailingIcon = {
                ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded)
            },
            modifier = Modifier
                .fillMaxWidth()
        )

        ExposedDropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
            options.forEach { option: String ->
                DropdownMenuItem(
                    content = { Text(text = option) },
                    onClick = {
                        expanded = false
                        onValueChangedEvent(option)
                    }
                )
            }
        }
    }
}

使用示例

CustomExposedDropDown(
    label = {
        TranslatedText(Translation.SUGGESTED_SERVERS.msg())
    },
    items = serverOptions.map {
        {
            Text(it.displayName)
        }
    },
    onChange = {
        screenModel.setSuggestedServer(serverOptions[it])
    },
    modifier = Modifier
        .width(200.dp)
        .align(Alignment.CenterHorizontally)
        .padding(bottom = 10.dp)
)

已尝试的解决方法

  • 更新所有依赖;
  • 实现两种不同类型的下拉菜单。

解决方案

1. 移除CustomExposedDropDown中的空clickable回调

CustomExposedDropDown内的Box设置了空的.clickable(onClick = {}),会拦截点击事件并干扰菜单选项的交互逻辑。直接移除该clickable修饰符即可:

Box(
    contentAlignment = Alignment.Center,
    modifier = Modifier
        .fillMaxWidth()
        .heightIn(min = 36.dp)
        .background(
            color = MaterialTheme.colors.onSurface.copy(alpha = TextFieldDefaults.BackgroundOpacity),
            shape = RoundedCornerShape(10.dp)
        )
    // 移除 .clickable(onClick = {})
)

2. 用rememberSaveable替代remember保存展开状态

Voyager导航可能导致页面重组时状态丢失,改用rememberSaveable持久化展开状态,避免交互异常:

// 原代码
var isExpanded by remember { mutableStateOf(false) }
// 修改为
var isExpanded by rememberSaveable { mutableStateOf(false) }

该修改需同时应用在CustomExposedDropDown和DynamicSelectTextField两个组件中。

3. 确保菜单锚点关联正确

若使用Material3版本的Compose,需给ExposedDropdownMenu添加.menuAnchor()修饰符,确保与ExposedDropdownMenuBox的布局上下文正确关联:

ExposedDropdownMenu(
    expanded = isExpanded,
    onDismissRequest = { isExpanded = false },
    modifier = Modifier.menuAnchor()
) {
    // 菜单选项内容
}

4. 排查布局遮挡问题

检查父布局是否存在透明覆盖层、高优先级的pointerInput或其他点击拦截逻辑,确保ExposedDropdownMenu的层级处于最上层,没有被其他布局遮挡。


内容的提问来源于stack exchange,提问作者SehrGuterCode

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 02:14:57