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

Compose ExposedDropdownMenu在Edge-to-Edge模式下的系统栏显示问题

解决ExposedDropdownMenu点击时导航栏自动弹出的问题

问题根源

ExposedDropdownMenu的PopupWindow在显示时,默认会触发系统栏Insets的重新计算,导致Edge-to-Edge模式下隐藏的导航栏被自动唤起,进而改变页面布局高度,引发菜单位置计算异常(如向上弹出、卡顿)。

解决方案

通过监听下拉菜单的展开/收起事件,手动控制其PopupWindow的系统栏行为,强制保持导航栏隐藏:

单个菜单处理示例

// 假设你的下拉菜单为MaterialAutoCompleteTextView实例
val dropdownMenu = binding.yourDropdownMenuId
dropdownMenu.setOnExpandListener(object : ExposedDropdownMenu.OnExpandListener {
    override fun onExpand(isExpanded: Boolean) {
        dropdownMenu.popupWindow?.let { popupWindow ->
            val activity = popupWindow.contentView.context as? Activity ?: return@let
            val insetsController = WindowInsetsControllerCompat(activity.window, popupWindow.contentView)
            
            if (isExpanded) {
                // 展开时强制隐藏导航栏,并设置仅通过滑动唤起导航栏
                insetsController.hide(WindowInsetsCompat.Type.systemBars())
                insetsController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_SWIPE
                // 确保PopupWindow独占触摸事件,避免触发系统栏
                popupWindow.setTouchModal(true)
                // 设置布局类型,避免触发系统栏Insets重计算
                PopupWindowCompat.setWindowLayoutType(popupWindow, WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL)
            } else {
                // 收起菜单后恢复原有系统栏行为
                insetsController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
            }
        }
    }
})

多菜单统一处理

如果存在多个ExposedDropdownMenu,可以封装工具方法批量配置:

fun setupDropdownSystemBarBehavior(dropdown: MaterialAutoCompleteTextView) {
    dropdown.setOnExpandListener(object : ExposedDropdownMenu.OnExpandListener {
        override fun onExpand(isExpanded: Boolean) {
            dropdown.popupWindow?.let { popup ->
                val activity = popup.contentView.context as? Activity ?: return
                val controller = WindowInsetsControllerCompat(activity.window, popup.contentView)
                
                if (isExpanded) {
                    controller.hide(WindowInsetsCompat.Type.systemBars())
                    controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_SWIPE
                    popup.setTouchModal(true)
                    PopupWindowCompat.setWindowLayoutType(popup, WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL)
                } else {
                    controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
                }
            }
        }
    })
}

// 使用方式
setupDropdownSystemBarBehavior(binding.dropdownMenu1)
setupDropdownSystemBarBehavior(binding.dropdownMenu2)

关键说明

  • setTouchModal(true):让PopupWindow消费所有触摸事件,防止事件透传到底层触发系统栏显示
  • TYPE_APPLICATION_SUB_PANEL:指定PopupWindow的布局类型,避免触发系统栏Insets的重新计算
  • 切换系统栏行为:展开时改为仅通过滑动唤起导航栏,收起后恢复原有的"短暂显示"行为,保留原有交互逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 06:05:18