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

如何在Flutter中实现点击可展开的DropDownButton扩展下拉菜单?

Flutter 点击展开下拉菜单实现方案

如果你使用默认DropdownButton无法满足自定义样式、交互需求,可以参考以下两种常用实现方案:

方案1:点击弹出悬浮下拉选项(基于PopupMenuButton)

适合需要点击按钮后弹出悬浮选项列表的场景,原生组件不需要额外依赖:

import 'package:flutter/material.dart';

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

  @override
  State<DropdownDemo> createState() => _DropdownDemoState();
}

class _DropdownDemoState extends State<DropdownDemo> {
  String selectedValue = '选项1';

  @override
  Widget build(BuildContext context) {
    return Center(
      child: PopupMenuButton<String>(
        // 自定义触发按钮样式
        child: Container(
          padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
          decoration: BoxDecoration(
            border: Border.all(color: Colors.grey),
            borderRadius: BorderRadius.circular(4),
          ),
          child: Row(
            mainAxisSize: MainAxisSize.min,
            children: [
              Text(selectedValue),
              const SizedBox(width: 8),
              const Icon(Icons.arrow_drop_down),
            ],
          ),
        ),
        // 下拉选项配置
        onSelected: (value) {
          setState(() {
            selectedValue = value;
          });
        },
        itemBuilder: (context) => [
          const PopupMenuItem(value: '选项1', child: Text('选项1')),
          const PopupMenuItem(value: '选项2', child: Text('选项2')),
          const PopupMenuItem(value: '选项3', child: Text('选项3')),
        ],
      ),
    );
  }
}

你可以通过修改offset属性调整下拉框弹出的位置,修改color、shape属性自定义下拉框的样式。

方案2:下方平滑展开下拉菜单(自定义实现)

如果需要下拉菜单直接展开在触发按钮下方、不悬浮覆盖其他区域,可以通过状态控制+动画实现:

import 'package:flutter/material.dart';

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

  @override
  State<ExpandableDropdown> createState() => _ExpandableDropdownState();
}

class _ExpandableDropdownState extends State<ExpandableDropdown> with SingleTickerProviderStateMixin {
  bool _isExpanded = false;
  late AnimationController _controller;
  late Animation<double> _heightAnimation;
  final List<String> _options = ['选项1', '选项2', '选项3', '选项4'];
  String _selectedOption = '请选择';

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 200));
    _heightAnimation = Tween<double>(begin: 0, end: 200).animate(CurvedAnimation(parent: _controller, curve: Curves.easeInOut));
  }

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

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

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.all(16),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          // 触发按钮
          GestureDetector(
            onTap: _toggleExpand,
            child: Container(
              padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
              decoration: BoxDecoration(
                border: Border.all(color: Colors.grey.shade300),
                borderRadius: BorderRadius.circular(8),
              ),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Text(_selectedOption),
                  Icon(_isExpanded ? Icons.arrow_drop_up : Icons.arrow_drop_down),
                ],
              ),
            ),
          ),
          // 展开的下拉列表
          AnimatedBuilder(
            animation: _heightAnimation,
            builder: (context, child) {
              return Container(
                height: _heightAnimation.value,
                margin: const EdgeInsets.only(top: 4),
                decoration: BoxDecoration(
                  border: Border.all(color: Colors.grey.shade300),
                  borderRadius: BorderRadius.circular(8),
                ),
                child: ListView.builder(
                  padding: EdgeInsets.zero,
                  itemCount: _options.length,
                  itemBuilder: (context, index) {
                    return ListTile(
                      title: Text(_options[index]),
                      onTap: () {
                        setState(() {
                          _selectedOption = _options[index];
                          _toggleExpand();
                        });
                      },
                    );
                  },
                ),
              );
            },
          )
        ],
      ),
    );
  }
}

你可以根据需求调整动画时长、下拉列表高度、各个组件的样式,也可以扩展多选等功能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 07:06:03