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

如何实现锚点固定且子菜单宽度与锚点一致的Flutter菜单?

实现带静态锚点且宽度匹配的展开菜单

要实现你需要的静态锚点菜单(锚点文本不随选中项变化,且子菜单宽度与锚点一致),可以通过MenuAnchor配合自定义布局控制来实现,以下是具体方案:

核心思路

  • 用固定文本的组件作为MenuAnchor的锚点,避免选中项替换锚点内容
  • 通过LayoutBuilder获取锚点的实际宽度,将该宽度应用到弹出的菜单容器上
  • 自定义菜单选项的交互逻辑,点击后仅执行业务操作,不修改锚点文本

完整代码示例

import 'package:flutter/material.dart';

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

  @override
  State<StaticAnchorMenu> createState() => _StaticAnchorMenuState();
}

class _StaticAnchorMenuState extends State<StaticAnchorMenu> {
  final MenuController _menuController = MenuController();
  double _anchorWidth = 0;

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

  @override
  Widget build(BuildContext context) {
    return MenuAnchor(
      controller: _menuController,
      menuChildren: [
        // 用Container约束菜单宽度与锚点一致
        SizedBox(
          width: _anchorWidth,
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              _buildMenuItem('选项1', () => _handleMenuTap('选项1')),
              _buildMenuItem('选项2', () => _handleMenuTap('选项2')),
              _buildMenuItem('选项3', () => _handleMenuTap('选项3')),
            ],
          ),
        ),
      ],
      builder: (context, controller, child) {
        return LayoutBuilder(
          builder: (context, constraints) {
            // 获取锚点的宽度
            _anchorWidth = constraints.maxWidth;
            return TextButton(
              style: TextButton.styleFrom(
                padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
                backgroundColor: Colors.grey[100],
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(4),
                ),
              ),
              onPressed: () {
                if (controller.isOpen) {
                  controller.close();
                } else {
                  controller.open();
                }
              },
              child: const Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Text('静态锚点菜单'),
                  Icon(Icons.arrow_drop_down),
                ],
              ),
            );
          },
        );
      },
    );
  }

  Widget _buildMenuItem(String text, VoidCallback onTap) {
    return InkWell(
      onTap: () {
        _menuController.close();
        onTap();
      },
      child: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
        child: Align(
          alignment: Alignment.centerLeft,
          child: Text(text),
        ),
      ),
    );
  }

  void _handleMenuTap(String option) {
    // 这里处理选项点击后的业务逻辑
    debugPrint('选中了:$option');
  }
}

// 使用示例
void main() {
  runApp(const MaterialApp(
    home: Scaffold(
      body: Center(
        child: StaticAnchorMenu(),
      ),
    ),
  ));
}

关键细节说明

  • 静态锚点:锚点用TextButton搭配固定文本实现,点击仅控制菜单的展开/收起,不会被选中项替换
  • 宽度匹配:通过LayoutBuilder获取锚点组件的最大宽度,将该值传递给菜单的SizedBox,确保菜单宽度与锚点完全一致
  • 菜单交互:自定义InkWell作为选项容器,点击后先关闭菜单再执行逻辑,体验更流畅

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 11:32:40