如何在 Flutter 中使用菜单下的项目(而不是弹出窗口)创建单选菜单

问题描述 投票:0回答:2

我想创建一个按钮来打开菜单来选择一个项目。但我希望菜单不是弹出式的,而是构建在按钮下。请参阅设计以供参考。

有图书馆可以做到这一点吗?或者我应该从头开始编程?

有像“DropdownButton2”和“DropdownButton”这样的小部件,将小部件菜单显示为弹出窗口。我想要同样的东西,但它显示了按钮下构建的菜单中的元素并占用空间,并且不覆盖菜单下的其他元素,如设计。

Design

您可以在这个设计中看到菜单不是弹出式的。

flutter
2个回答
1
投票

不幸的是,似乎没有一个流行的库可以做到这一点。此设计可以使用 ExpansionTile 来实现 — 事实证明,使用

ExpansionTile
比使用
ExpansionPanel
更容易,因为后者必须与
ExpansionPanelList
一起使用,而在默认的 Material 设计之外很难进行自定义。

这是一个尽可能接近您的设计的示例实现,您可以对其进行更改以满足您的需求。

class ExpandingMenu extends StatefulWidget {
  final List<String> menuOptions;

  const ExpandingMenu({super.key, required this.menuOptions});

  @override
  State<ExpandingMenu> createState() => _ExpandingMenuState();
}

class _ExpandingMenuState extends State<ExpandingMenu> {
  String? _selectedOption;
  final _controller = ExpansionTileController();
  bool _isExpanded = false;

  @override
  Widget build(BuildContext context) {
    final outlineColor = Theme.of(context).colorScheme.outlineVariant;

    return Theme(
      data: Theme.of(context).copyWith(
        // This is required to remove the default dividers around the
        // ExpansionTile
        dividerColor: Colors.transparent,
      ),
      child: ExpansionTile(
        showTrailingIcon: false,
        tilePadding: EdgeInsets.zero,
        controller: _controller,
        onExpansionChanged: (value) => setState(() => _isExpanded = value),
        title: Container(
          padding: const EdgeInsets.all(10),
          decoration: BoxDecoration(
            border: Border.all(
              color: _isExpanded ? Colors.lightBlueAccent : outlineColor,
              width: 2,
            ),
            borderRadius: BorderRadius.circular(5),
          ),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Text(
                _selectedOption ?? 'Vorlage aussuchen',
                style: TextStyle(
                  color: (_isExpanded || _selectedOption != null)
                      ? Colors.black
                      : Colors.grey,
                  fontSize: 16,
                  fontWeight: FontWeight.bold,
                ),
              ),
              Transform.rotate(
                angle: pi / 2,
                child: const Icon(
                  Icons.chevron_right_rounded,
                  color: Colors.lightBlueAccent,
                ),
              ),
            ],
          ),
        ),
        children: [
          Container(
            padding: const EdgeInsets.all(10),
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(5),
              border: Border.all(
                color: outlineColor,
                width: 2,
              ),
            ),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                for (String option in widget.menuOptions)
                  GestureDetector(
                    onTap: () => setState(() {
                      _selectedOption = option;
                      _controller.collapse();
                    }),
                    child: Text(
                      option,
                      style: const TextStyle(
                        fontSize: 16,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ),
              ].expand((e) => [e, const Divider(height: 20)]).toList()
                ..removeLast(), // Remove the trailing divider
            ),
          ),
        ],
      ),
    );
  }
}

就你而言:

ExpandingMenu(
  menuOptions: ['keine Auswahl', 'Vorlage 1', 'Vorlage 2'],
)

结果

Screen recording of result


0
投票

我见过的大多数库都会在其他内容上弹出,因此您可能需要从头开始构建一些东西。

构建这样的东西应该不会太难。您可以构建一个显示/隐藏内容的自定义小部件,也可以将这些选项放在 ExpansionPanel

© www.soinside.com 2019 - 2024. All rights reserved.