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

Jetpack Compose ExposedDropdownMenu高度超20dp时总是向上展开问题

问题:ExposedDropdownMenu高度超过20dp时向上展开的问题

我在实现ExposedDropdownMenu,希望它显示在TextField下方。但发现只要下拉菜单高度超过20dp,它就会向上展开,只有高度≤20dp时才会正常向下显示。

效果展示:
下拉菜单向上展开的效果

我的代码:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TextFieldWithDropdown(
    modifier: Modifier = Modifier,
    textFieldState: TextFieldState,
    textCallback: (String) -> Unit,
    list: List<String>,
    keyboardOptions: KeyboardOptions,
    textStyle: TextStyle
) {
    val dropDownOptions = remember { mutableStateOf(listOf<String>()) }
    val textFieldValue = remember { mutableStateOf(TextFieldValue()) }
    val dropDownExpanded = remember { mutableStateOf(false) }

    ExposedDropdownMenuBox(
        modifier = modifier,
        expanded = dropDownExpanded.value, onExpandedChange = {
            dropDownExpanded.value = !dropDownExpanded.value
        }) {
        TextField(
            modifier = Modifier
                .menuAnchor()
                .fillMaxWidth()
                .onFocusChanged { focusState ->
                    if (!focusState.isFocused)
                        dropDownExpanded.value = false
                },
            value = textFieldState.text.value,
            onValueChange = {
                textFieldState.text.value = it
                textCallback.invoke(it)
                dropDownOptions.value =
                    list.filter { it.startsWith(textFieldState.text.value) && it != textFieldState.text.value }
                        .take(3)
                dropDownExpanded.value = dropDownOptions.value.isNotEmpty()
            },
            singleLine = true,
            maxLines = 1,
            textStyle = textStyle,
        )
        ExposedDropdownMenu(
            expanded = dropDownExpanded.value,
            onDismissRequest = {
                dropDownExpanded.value = false
            },
        ) {
            dropDownOptions.value.forEach { text ->
                DropdownMenuItem(text = {
                    Text(text = text)
                }, onClick = {
                    textFieldState.text.value = text
                    dropDownExpanded.value = false
                })
            }
        }
    }
}

解决方案

问题原因

ExposedDropdownMenu默认会根据屏幕可用空间自动调整展开方向:当TextField下方的剩余空间不足以容纳菜单高度时,组件会自动切换为向上展开。高度超过20dp时,当前布局下方的空间刚好不足以容纳菜单,触发了这个自动适配逻辑。

解决方法

1. 强制固定展开方向

给ExposedDropdownMenu添加对齐方式和偏移参数,强制菜单从TextField底部向下展开:

ExposedDropdownMenu(
    expanded = dropDownExpanded.value,
    onDismissRequest = { dropDownExpanded.value = false },
    // 强制菜单顶部与TextField底部对齐
    expandedAlignment = Alignment.TopStart,
    // 偏移量设置为TextField的高度,确保菜单紧贴下方
    expandedOffset = DpOffset(0.dp, TextFieldDefaults.MinHeight)
) {
    dropDownOptions.value.forEach { text ->
        DropdownMenuItem(text = {
            Text(text = text)
        }, onClick = {
            textFieldState.text.value = text
            dropDownExpanded.value = false
        })
    }
}

2. 确保父布局有足够空间

检查TextFieldWithDropdown的父布局约束:

  • 如果父布局是Column,可以添加滚动让内容能向下扩展:
Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
    TextFieldWithDropdown(/* 参数 */)
}
  • 避免父布局设置固定高度或被其他组件挤压,保证TextField下方有足够空间容纳菜单。

3. 限制菜单高度并启用内部滚动

既保证显示足够选项,又避免菜单高度过大触发向上展开:

ExposedDropdownMenu(
    expanded = dropDownExpanded.value,
    onDismissRequest = { dropDownExpanded.value = false },
    // 限制菜单最大高度,超出部分内部滚动
    modifier = Modifier.maxHeight(150.dp).verticalScroll(rememberScrollState())
) {
    dropDownOptions.value.forEach { text ->
        DropdownMenuItem(text = {
            Text(text = text)
        }, onClick = {
            textFieldState.text.value = text
            dropDownExpanded.value = false
        })
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 09:25:14