Flutter中如何创建可展开卡片列表的下拉Widget组件
Flutter实现点击展开卡片下拉列表
你遇到的expansionCallback逻辑不清晰的问题,核心是没有理解这个组件的状态更新机制:ExpansionPanelList本身是无状态的,展开/收起的状态需要你自己在StatefulWidget中维护,expansionCallback就是点击头部触发的状态更新入口。
核心参数说明
expansionCallback(panelIndex, isExpanded):点击面板头部时触发的回调panelIndex:当前被点击的面板在children数组中的索引值isExpanded:点击动作触发前,对应面板的当前展开状态
- 每个
ExpansionPanel组件的isExpanded属性,必须和你自己维护的状态变量绑定,状态更新后组件会自动执行展开/收起的过渡动画,不需要手动写动画控制逻辑。
注意:
ExpansionPanelList是无状态组件,自身不会维护展开/收起状态,必须放在StatefulWidget中使用,通过setState更新状态才能触发UI变化。
可直接运行的实现代码
这个代码实现的效果和参考截图交互一致:点击彩色头部展开白色卡片列表,再次点击收起。
import 'package:flutter/material.dart'; class ExpandableListPage extends StatefulWidget { const ExpandableListPage({super.key}); @override State<ExpandableListPage> createState() => _ExpandableListPageState(); } class _ExpandableListPageState extends State<ExpandableListPage> { // 存储面板的展开状态,初始为收起状态 bool _panelExpanded = false; @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey[100], appBar: AppBar(title: const Text('展开列表示例')), body: Padding( padding: const EdgeInsets.all(16), child: ExpansionPanelList( elevation: 3, // 展开回调核心逻辑 expansionCallback: (panelIndex, isExpanded) { setState(() { // 将当前面板状态取反,触发UI重建 _panelExpanded = !isExpanded; }); }, children: [ ExpansionPanel( // 绑定展开状态 isExpanded: _panelExpanded, backgroundColor: Colors.green, headerBuilder: (context, isExpanded) { return const ListTile( title: Text( 'Campionati Appuntati', style: TextStyle( color: Colors.white, fontSize: 16, fontWeight: FontWeight.w500 ), ), ); }, // 展开后的列表内容区 body: Column( children: [ ListTile( tileColor: Colors.white, title: const Text('Serie A'), trailing: const Icon(Icons.chevron_right, color: Colors.grey), onTap: () { // 子项点击逻辑写在这里 }, ), const Divider(height: 1, color: Color(0xFFF0F0F0)), ListTile( tileColor: Colors.white, title: const Text('Premier League'), trailing: const Icon(Icons.chevron_right, color: Colors.grey), onTap: () {}, ), const Divider(height: 1, color: Color(0xFFF0F0F0)), ListTile( tileColor: Colors.white, title: const Text('La Liga'), trailing: const Icon(Icons.chevron_right, color: Colors.grey), onTap: () {}, ), ], ), ) ], ), ), ); } }
多面板场景适配
如果你需要做多个可展开的下拉按钮,把单个bool状态改成对应数量的状态列表即可:
- 定义状态列表:
List<bool> _panelStateList = List.generate(面板总数, (index) => false); - 每个
ExpansionPanel的isExpanded绑定对应索引的状态:isExpanded: _panelStateList[index] - 回调中更新对应索引的状态:
expansionCallback: (panelIndex, isExpanded) { setState(() { _panelStateList[panelIndex] = !isExpanded; }); }
样式调整技巧
- 去掉面板默认分割线:给
ExpansionPanelList加dividerColor: Colors.transparent - 调整展开/收起动画速度:组件默认动画时长为200ms,符合常规移动端交互体验,无需额外修改
- 调整头部内边距:修改
expandedHeaderPadding参数即可适配设计稿尺寸要求
内容的提问来源于stack exchange,提问作者faccio
相关产品推荐
相关产品推荐

