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

Flutter:如何让PopupMenuItem始终显示在选中项下方并滚动?

解决PopupMenuButton菜单位置异常及滚动支持问题

问题描述

当PopupMenuItem数量较少(2-9个)时,菜单正常显示在选中项下方;但数量超过10个时,菜单会从屏幕顶部开始显示,而非选中项下方。需要确保菜单始终显示在选中项下方,且支持滚动展示所有项。

原代码示例

PopupMenuButton<Guru>(
  onSelected: _onSelectGuru,
  itemBuilder: (context) => [
    ...widget.wisdomData.gurus.map(
      (guru) => PopupMenuItem<Guru>(
        value: guru,
        child: Text(
          guru.name,
          style: const TextStyle(color: Colors.white),
        ),
      ),
    ),
    const PopupMenuItem<Guru>(
      value: null,
      child: Text(
        'Random',
        style: TextStyle(color: Colors.white),
      ),
    ),
  ],
  position: PopupMenuPosition.under,
  color: Colors.transparent,
  elevation: 0,
  child: Container(
    decoration: const BoxDecoration(color: Colors.transparent),
    padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
    child: Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        Text(
          selectedGuru.name,
          style: const TextStyle(color: Colors.white),
        ),
        const Icon(
          Icons.arrow_drop_down,
          color: Colors.white,
        ),
      ],
    ),
  ),
)

解决方案

核心思路

PopupMenuButton默认会根据屏幕剩余空间自动切换菜单位置,即使设置了position: PopupMenuPosition.under也会失效。要固定位置,需限制菜单最大高度,同时用滚动组件包裹内容,确保菜单不会因内容过多超出下方屏幕空间。

修改后的代码实现

PopupMenuButton<Guru>(
  onSelected: _onSelectGuru,
  itemBuilder: (context) => [
    PopupMenuItem(
      padding: EdgeInsets.zero,
      child: SingleChildScrollView(
        physics: const AlwaysScrollableScrollPhysics(),
        child: Column(
          children: [
            ...widget.wisdomData.gurus.map(
              (guru) => PopupMenuItem<Guru>(
                value: guru,
                child: Text(
                  guru.name,
                  style: const TextStyle(color: Colors.white),
                ),
              ),
            ),
            const PopupMenuItem<Guru>(
              value: null,
              child: Text(
                'Random',
                style: TextStyle(color: Colors.white),
              ),
            ),
          ],
        ),
      ),
    ),
  ],
  position: PopupMenuPosition.under,
  color: Colors.transparent,
  elevation: 0,
  // 限制菜单最大高度为屏幕高度的一半,可根据需求调整比例
  constraints: BoxConstraints(
    maxHeight: MediaQuery.of(context).size.height * 0.5,
  ),
  child: Container(
    decoration: const BoxDecoration(color: Colors.transparent),
    padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
    child: Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        Text(
          selectedGuru.name,
          style: const TextStyle(color: Colors.white),
        ),
        const Icon(
          Icons.arrow_drop_down,
          color: Colors.white,
        ),
      ],
    ),
  ),
)

关键修改点说明

  • 用SingleChildScrollView包裹菜单内容:让超出高度限制的内容可滚动,避免菜单因内容过多触发系统位置调整。
  • 设置constraints限制最大高度:通过MediaQuery获取屏幕高度,固定菜单最大高度,确保下方有足够空间容纳菜单。
  • 移除外层PopupMenuItem默认padding:避免滚动区域出现多余内边距,保证布局紧凑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 21:23:20