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

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

目标效果展示

可展开表格收起状态
可展开表格展开状态

Flutter 可展开表格实现方案

不用依赖复杂第三方包,用Flutter基础组件就能实现这类可展开表格,核心是通过StatefulWidget管理每行的展开状态,结合DataTable和自定义展开区域实现。

核心实现思路

  1. 定义包含主行、子行数据的模型类
  2. 用列表存储每行的展开状态(布尔值)
  3. 构建主表格,给主行添加点击事件切换展开状态;展开时在主行下方渲染子内容区域

示例代码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 16:55:23