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

Flutter/Dart可复用表格组件:如何无类容器传递命名属性列表

几种Flutter中实现表格Widget与数据类解耦的方案

针对你想让表格Widget脱离特定Item类绑定、灵活接收不同数据结构的需求,这里有几个实用的实现思路:

1. 用Map传递数据 + 指定列Key(灵活无绑定)

这种方式直接用List<Map<String, dynamic>>承载数据,让表格通过Key取值渲染,完全不依赖任何自定义数据类。

表格Widget实现:

class GenericTable extends StatelessWidget {
  final List<Map<String, dynamic>> data;
  final List<String> columnKeys; // 对应要展示的属性Key
  final List<String> columnTitles; // 表头文字

  const GenericTable({
    super.key,
    required this.data,
    required this.columnKeys,
    required this.columnTitles,
  }) : assert(columnKeys.length == columnTitles.length, "列数需匹配");

  @override
  Widget build(BuildContext context) {
    return Table(
      border: TableBorder.all(),
      children: [
        // 表头行
        TableRow(
          children: columnTitles.map((title) => Padding(
            padding: const EdgeInsets.all(8.0),
            child: Text(title, style: const TextStyle(fontWeight: FontWeight.bold)),
          )).toList(),
        ),
        // 数据行
        ...data.map((row) => TableRow(
          children: columnKeys.map((key) => Padding(
            padding: const EdgeInsets.all(8.0),
            child: Text(row[key].toString()),
          )).toList(),
        )),
      ],
    );
  }
}

调用示例:

GenericTable(
  data: [
    {"name": "张三", "street": "中山路", "number": 101},
    {"name": "李四", "street": "解放路", "number": 202},
  ],
  columnKeys: ["name", "street", "number"],
  columnTitles: ["姓名", "街道", "门牌号"],
)

优点:完全解耦,任何带对应Key的Map都能传;缺点:无类型校验,Key写错会导致空值,适合快速迭代场景。

2. 泛型+回调函数(类型安全,扩展性强)

这种方案用泛型支持任意数据类型,通过回调函数定义每个列如何从数据对象中取值,既保留灵活性又有类型安全保障。

表格Widget实现:

// 定义列配置类,封装表头和取值逻辑
class TableColumn<T> {
  final String title;
  final dynamic Function(T item) valueExtractor;

  const TableColumn({required this.title, required this.valueExtractor});
}

class TypedGenericTable<T> extends StatelessWidget {
  final List<T> items;
  final List<TableColumn<T>> columns;

  const TypedGenericTable({
    super.key,
    required this.items,
    required this.columns,
  });

  @override
  Widget build(BuildContext context) {
    return Table(
      border: TableBorder.all(),
      children: [
        // 表头
        TableRow(
          children: columns.map((col) => Padding(
            padding: const EdgeInsets.all(8.0),
            child: Text(col.title, style: const TextStyle(fontWeight: FontWeight.bold)),
          )).toList(),
        ),
        // 数据行
        ...items.map((item) => TableRow(
          children: columns.map((col) => Padding(
            padding: const EdgeInsets.all(8.0),
            child: Text(col.valueExtractor(item).toString()),
          )).toList(),
        )),
      ],
    );
  }
}

调用示例:

场景1:用Map数据

TypedGenericTable<Map<String, dynamic>>(
  items: [
    {"name": "王五", "street": "建国路", "number": 303},
    {"name": "赵六", "street": "复兴路", "number": 404},
  ],
  columns: [
    TableColumn(title: "姓名", valueExtractor: (row) => row["name"]),
    TableColumn(title: "街道", valueExtractor: (row) => row["street"]),
    TableColumn(title: "门牌号", valueExtractor: (row) => row["number"]),
  ],
)

场景2:用自定义类(比如原有Item类)

// 原有Item类
class Item {
  final String name;
  final String street;
  final int number;

  Item(this.name, this.street, this.number);
}

// 调用表格
TypedGenericTable<Item>(
  items: [
    Item("孙七", "光明路", 505),
    Item("周八", "幸福路", 606),
  ],
  columns: [
    TableColumn(title: "姓名", valueExtractor: (item) => item.name),
    TableColumn(title: "街道", valueExtractor: (item) => item.street),
    TableColumn(title: "门牌号", valueExtractor: (item) => item.number),
  ],
)

优点:类型安全,编译期就能发现取值逻辑错误;支持任意数据类型,扩展性拉满;缺点:需要额外定义列配置类,代码量稍多。

3. 直接传递List(极简但易出错)

如果想贴近你说的List<[name, street, number]>结构,可以用List<List<dynamic>>传递数据,但这种方式没有属性命名,完全依赖顺序匹配,可读性和维护性差,不推荐用于复杂场景:

调用示例(表格实现类似方案1,遍历List而非Map):

GenericListTable(
  data: [
    ["钱九", "朝阳路", 707],
    ["吴十", "海淀路", 808],
  ],
  columnTitles: ["姓名", "街道", "门牌号"],
)

优点:代码极简;缺点:顺序错了直接展示混乱,无类型校验,后期维护容易出问题。

综合来看,泛型+回调函数的方案是最优解,既满足解耦需求,又保障类型安全,适合长期维护的项目;如果是快速原型开发,用Map的方案更高效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 03:53:13