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

Flutter如何创建按钮下方展开的非弹窗式单选菜单

实现非弹窗式展开选择菜单的方案

现成组件库推荐

  • expandable:这个库可将任意组件包装为可展开/收起的容器,你能把按钮和菜单内容放在同一个ExpandablePanel中,点击按钮触发展开后,菜单会直接在按钮下方延伸,自然占据页面空间,不会覆盖其他元素。通过controller即可控制展开状态,菜单内容支持完全自定义。
  • flutter_collapsible:专注于折叠/展开UI的轻量库,同样能实现按钮下方展开菜单的效果,支持自定义动画过渡,展开时会自动推动下方元素下移,完全匹配你的需求。

自行开发方案(现有库不满足需求时)

如果不想依赖第三方库,自己实现也很简单,核心是通过状态管理控制菜单显隐,结合动画过渡实现平滑效果:

  1. 用StatefulWidget维护isExpanded状态变量,控制菜单的展开/收起状态。
  2. 将按钮和菜单放在同一个Column布局中,菜单部分用SizeTransition或AnimatedContainer包裹,实现展开/收起的平滑动画。
  3. 给按钮添加点击事件,切换isExpanded状态,菜单展开时会自动占据空间,推动下方元素下移。

示例代码片段:

class ExpandableMenuButton extends StatefulWidget {
  const ExpandableMenuButton({super.key});

  @override
  State<ExpandableMenuButton> createState() => _ExpandableMenuButtonState();
}

class _ExpandableMenuButtonState extends State<ExpandableMenuButton> with SingleTickerProviderStateMixin {
  bool _isExpanded = false;
  late AnimationController _controller;
  late Animation<double> _heightAnimation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(milliseconds: 300),
      vsync: this,
    );
    _heightAnimation = Tween<double>(begin: 0, end: 150).animate(_controller);
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  void _toggleExpanded() {
    setState(() {
      _isExpanded = !_isExpanded;
      _isExpanded ? _controller.forward() : _controller.reverse();
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        ElevatedButton(
          onPressed: _toggleExpanded,
          child: Text(_isExpanded ? '收起菜单' : '展开菜单'),
        ),
        SizeTransition(
          sizeFactor: _heightAnimation.drive(Tween<double>(begin: 0, end: 1)),
          axisAlignment: -1.0,
          child: Container(
            height: 150,
            color: Colors.grey[200],
            child: const Column(
              children: [
                ListTile(title: Text('选项1')),
                ListTile(title: Text('选项2')),
                ListTile(title: Text('选项3')),
              ],
            ),
          ),
        ),
        // 下方元素会被展开的菜单推动下移
        const Text('下方的内容'),
      ],
    );
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 10:07:38