如何在Flutter中实现如图所示的可展开表格(Expandable Table)UI?
目标效果展示


Flutter 可展开表格实现方案
不用依赖复杂第三方包,用Flutter基础组件就能实现这类可展开表格,核心是通过StatefulWidget管理每行的展开状态,结合DataTable和自定义展开区域实现。
核心实现思路
- 定义包含主行、子行数据的模型类
- 用列表存储每行的展开状态(布尔值)
- 构建主表格,给主行添加点击事件切换展开状态;展开时在主行下方渲染子内容区域
示例代码
import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: const Text("可展开表格")), body: const ExpandableTable(), ), ); } } // 表格行数据模型:包含主行信息和子行列表 class TableRowData { final String id; final String name; final String value; final List<String> subRows; TableRowData({ required this.id, required this.name, required this.value, required this.subRows, }); } class ExpandableTable extends StatefulWidget { const ExpandableTable({super.key}); @override State<ExpandableTable> createState() => _ExpandableTableState(); } class _ExpandableTableState extends State<ExpandableTable> { // 模拟表格数据源 final List<TableRowData> _tableData = [ TableRowData( id: "1", name: "项目A", value: "100", subRows: ["子项A1: 50", "子项A2: 30", "子项A3: 20"], ), TableRowData( id: "2", name: "项目B", value: "200", subRows: ["子项B1: 100", "子项B2: 80", "子项B3: 20"], ), ]; // 存储每行的展开状态,默认全部收起 late List<bool> _expandedStates; @override void initState() { super.initState(); _expandedStates = List.generate(_tableData.length, (_) => false); } // 切换指定行的展开/收起状态 void _toggleExpand(int index) { setState(() { _expandedStates[index] = !_expandedStates[index]; }); } @override Widget build(BuildContext context) { return SingleChildScrollView( child: Column( children: [ // 主表格区域 DataTable( columns: const [ DataColumn(label: Text("ID")), DataColumn(label: Text("名称")), DataColumn(label: Text("数值")), DataColumn(label: Text("操作")), ], rows: List.generate(_tableData.length, (index) { final data = _tableData[index]; return DataRow( onSelectChanged: (_) => _toggleExpand(index), cells: [ DataCell(Text(data.id)), DataCell(Text(data.name)), DataCell(Text(data.value)), DataCell( Icon( _expandedStates[index] ? Icons.expand_less : Icons.expand_more, ), ), ], ); }), ), // 展开的子内容区域 for (int i = 0; i < _tableData.length; i++) if (_expandedStates[i]) Container( width: double.infinity, color: Colors.grey[100], padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: _tableData[i].subRows.map((sub) => Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Text(sub), )).toList(), ), ), ], ), ); } }
自定义说明
- 点击主表格任意一行(或操作列图标)即可切换展开状态
- 子内容区域可根据需求修改样式,比如替换为子表格、卡片组件等
- 如果需要更复杂的嵌套表格结构,直接将展开区域替换为
DataTable即可
内容的提问来源于stack exchange,提问作者Danish Maula
相关产品推荐
相关产品推荐

