如何在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
相关产品推荐
相关产品推荐

