Flutter表格布局插件flextable的使用

Flutter表格布局插件FlexTable的使用

FlexTable 是一个可自定义的表格,包含表头、分割视图、冻结视图、自动冻结、缩放和滚动条。表格由模型(model)、视图模型(viewmodel)和构建器(builders)组成。如图1所示,展示了部分选项。FlexTable 支持双向滚动。如果在垂直或水平方向上的滚动偏移小于22.5度超过30个单位长度时,滚动稳定器将介入,防止在多个页面上因过度滚动而漂移。稳定器会纠正交叉滚动方向的漂移,因此可能会看到轻微的摆动。滚动条仅在拖动开始后出现。(移动端)

此外,也可以将 FlexTable 放置在一个 CustomScrollView 中,通过包裹 FlexTable 在一个 adaptive sliver 中实现。包裹在 sliver 中的表格只能在同一时间单向滚动。

图1: 选项: A. 滚动方向, B. 拖动以初始化分割视图, C. 冻结/取消冻结, D. 更改冻结位置

使用

要使用此插件,在 pubspec.yaml 文件中添加 flextable 作为依赖项。

开始

要创建一个简单的 FlexTable,首先创建一个模型(DefaultFtModel),然后将其放入 DefaultFlexTable 小部件中。

模型

DefaultFtModel (FtModel<Cell>) 包含数据、行、单元格尺寸、分割选项、自动冻结等。单元格包含值及一些基本的单元格属性:{ 文本样式、对齐方式、背景色、百分比背景色、旋转 }。

final model = DefaultFtModel(
  defaultWidthCell: 120.0,
  defaultHeightCell: 50.0,
);

model.addCell(
  row: 0,
  column: 0,
  cell: Cell(
    value: 'Hello!',
    attr: {
      CellAttr.textStyle: const TextStyle(fontSize: 20, color: Colors.blue),
    },
  ),
);

// 添加行(见 表格行 段落)
model.horizontalLineList.addLineRange(...);

FlexTable

DefaultFlexTable (FlexTable<FtModel<Cell>, Cell>) 需要 DefaultFtModel 和 DefaultTableBuilder。默认情况下,启用缩放、冻结和分割(从右上角拖动)。可以通过添加 FtController 到 FlexTable 来获取 FtViewModel,以改变例如比例、分割、解锁等设置。

[@override](/user/override)
Widget build(BuildContext context) {
  return DefaultFlexTable(
    model: model,
    tableBuilder: DefaultTableBuilder(),
  );
}

FlexTable 在 CustomScrollView 中

FlexTable 可以放置在 CustomScrollView 中,并通过 FlexTableToSliverBox 包装。工作原理是从 FlexTableToSliverBox (RenderSliverSingleBoxAdapter) 确定表格的滚动,通过 constraints.scrollOffset + overlap 来确定滚动,窗口大小由 paintedChildSize 确定。目前在 CustomScrollView 中不支持双向滚动。

final ftController = DefaultFtController();

[@override](/user/override)
Widget build(BuildContext context) {
  return CustomScrollView(
    slivers: [
      // 其他 slivers...
      FlexTableToSliverBox(
        ftController: ftController,
        child: DefaultFlexTable(
          model: model,
          tableBuilder: DefaultTableBuilder(),
          ftController: ftController,
        ),
      ),
    ],
  );
}

自定义 FlexTable

目前默认设置较为基础,但可以扩展以下类来更改单元格属性、单元格构建、表格测量、如何接收单元格属性等:

  • FtModel<C extends AbstractCell> extends AbstractFtModel<C>
  • AbstractTableBuilder<T extends AbstractFtModel<C>, C extends AbstractCell>
  • FlexTable<T extends AbstractFtModel<C>, C extends AbstractCell>
  • FtController<T extends AbstractFtModel<C>, C extends AbstractCell>
  • AbstractCell

表格行

垂直线和水平线分别单独添加到表格中,以减少大表格中的对象数量。TableLinesOneDirection 对象包含一个 LineLinkedList,其中包含 LineRanges,这些 LineRanges 包含一个 LineLinkedList,其中包含 LineNodeRanges 用于一个方向。

垂直线和水平线以范围的形式分别添加到表格中,以最小化大表格中的对象数量。TableLinesOneDirection 对象包含一个 LineLinkedList,其中包含 LineRanges,这些 LineRanges 包含一个 LineLinkedList,其中包含 LineNodeRanges 用于一个方向。

可以通过添加 EmptyLineNodes(带有无线条的 LineNode)覆盖所需范围来删除线条或线条的一部分。TableLinesOneDirection 对象将删除合并了 EmptyLineNode 的线条。如果 LineRange 为空,则自动删除 LineRange。

可以通过使用 Line.change(width:…, color…) 来更改现有线条的宽度和颜色。新的属性将与现有线条合并。

TableLinesOneDirection horizontalLines = TableLinesOneDirection();
// 或者使用已初始化的 FtModel -> ftModel.horizontalLines

const blueLine = Line(
  width: 0.5,
  color: Color(0xFF42A5F5),
);

/// 0: --  --
/// 1: --  --
/// 2: --  --

horizontalLines.addLineRange(LineRange(
  startIndex: 0,
  endIndex: 2,
  lineNodeRange: LineNodeRange(list: [
    LineNode(startIndex: 0, after: blueLine),
    LineNode(startIndex: 2, before: blueLine),
    LineNode(startIndex: 4, after: blueLine),
    LineNode(startIndex: 6, before: blueLine),
  ]),
));

示例代码

以下是一个完整的示例代码,展示了如何使用 FlexTable。

import 'package:flextable/flextable.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      theme: ThemeData(
          useMaterial3: true,
          colorScheme: ColorScheme.fromSeed(
              seedColor: const Color.fromARGB(255, 229, 235, 206))),
      home: const ShortExample(),
    ),
  );
}

class ShortExample extends StatefulWidget {
  const ShortExample({super.key});

  [@override](/user/override)
  State<ShortExample> createState() => _ShortExampleState();
}

class _ShortExampleState extends State<ShortExample> {
  [@override](/user/override)
  Widget build(BuildContext context) {
    const columns = 50;
    const rows = 5000;

    final model = DefaultFtModel(
      columnHeader: true,
      rowHeader: true,
      defaultWidthCell: 120.0,
      defaultHeightCell: 50.0,
      tableColumns: columns,
      tableRows: rows,
    );

    const line = Line(width: 0.5, color: Color.fromARGB(255, 70, 78, 38));

    for (int r = 0; r < rows; r++) {
      for (int c = 0; c < columns; c++) {
        int rows = 1;
        if ((c + 1) % 2 == 0) {
          if (r % 3 == 0) {
            rows = 3;
          } else {
            continue;
          }
        }
        Map attr = {
          CellAttr.background: (r % 99 < 1
              ? const Color.fromARGB(255, 249, 250, 245)
              : ((r % 2) % 2 == 0
                  ? Colors.white10
                  : const Color.fromARGB(255, 229, 235, 206))),
          CellAttr.textStyle: const TextStyle(
              fontSize: 20, color: Color.fromARGB(255, 70, 78, 38)),
        };

        model.addCell(
            row: r,
            column: c,
            cell: Cell(value: '${numberToCharacter(c)}$r', attr: attr),
            rows: rows);
      }
    }

    model.horizontalLines.addLineRanges((create) {
      for (int r = 0; r < rows; r += 3) {
        /// Horizontal lines
        ///
        ///
        create(LineRange(
            startIndex: r,
            lineNodeRange: LineNodeRange(list: [
              LineNode(
                startIndex: 0,
                after: line,
              ),
              LineNode(
                startIndex: 0,
                before: line,
              )
            ])));

        /// Horizontal lines for merged columns
        ///
        ///
        create(LineRange(
            startIndex: r + 1,
            endIndex: r + 2,
            lineNodeRange: LineNodeRange()
              ..addLineNodes((create) {
                for (int c = 0; c < columns; c += 2) {
                  create(LineNode(
                    startIndex: c,
                    after: line,
                  ));
                  create(LineNode(
                    startIndex: c + 1,
                    before: line,
                  ));
                }
              })));
      }
    });

    model.verticalLines.addLineRange(LineRange(
        startIndex: 0,
        endIndex: columns,
        lineNodeRange: LineNodeRange(list: [
          LineNode(
            startIndex: 0,
            after: line,
          ),
          LineNode(
            startIndex: rows,
            before: line,
          ),
        ])));

    model
      ..autoFreezeAreasY = [
        for (int r = 0; r < rows - 100; r += 99)
          AutoFreezeArea(startIndex: r, freezeIndex: r + 3, endIndex: r + 90)
      ]
      ..tableColumns = columns
      ..tableRows = rows;

    return Scaffold(
        appBar: AppBar(
          centerTitle: true,
          title: const Text('Short FlexTable example'),
        ),
        body: DefaultFlexTable(
          backgroundColor: Colors.white,
          model: model,
          tableBuilder: DefaultTableBuilder(),
        ));
  }
}

更多关于Flutter表格布局插件flextable的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter表格布局插件flextable的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


FlexTable 是 Flutter 中一个用于创建灵活表格布局的插件。它允许开发者轻松地创建复杂的表格,并且支持自定义行高、列宽、单元格内容等。以下是如何使用 FlexTable 的基本步骤和示例。

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 flextable 插件的依赖。

dependencies:
  flutter:
    sdk: flutter
  flextable: ^1.0.0  # 请检查最新版本

然后,运行 flutter pub get 来获取依赖。

2. 导入包

在你的 Dart 文件中导入 flextable 包。

import 'package:flextable/flextable.dart';

3. 创建表格

使用 FlexTable 来创建表格。你可以通过 columnsrows 属性来定义表格的列和行。

FlexTable(
  columns: [
    FlexColumn(label: 'ID', grow: 1),
    FlexColumn(label: 'Name', grow: 2),
    FlexColumn(label: 'Age', grow: 1),
  ],
  rows: [
    FlexRow(
      cells: [
        FlexCell(child: Text('1')),
        FlexCell(child: Text('John Doe')),
        FlexCell(child: Text('25')),
      ],
    ),
    FlexRow(
      cells: [
        FlexCell(child: Text('2')),
        FlexCell(child: Text('Jane Smith')),
        FlexCell(child: Text('30')),
      ],
    ),
  ],
);

4. 自定义表格样式

你可以通过设置 FlexTable 的各种属性来自定义表格样式,如边框、背景颜色、文本样式等。

FlexTable(
  border: TableBorder.all(color: Colors.black, width: 1),
  headerStyle: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
  cellStyle: TextStyle(fontSize: 14),
  headerBackgroundColor: Colors.grey[300],
  cellBackgroundColor: Colors.white,
  columns: [
    FlexColumn(label: 'ID', grow: 1),
    FlexColumn(label: 'Name', grow: 2),
    FlexColumn(label: 'Age', grow: 1),
  ],
  rows: [
    FlexRow(
      cells: [
        FlexCell(child: Text('1')),
        FlexCell(child: Text('John Doe')),
        FlexCell(child: Text('25')),
      ],
    ),
    FlexRow(
      cells: [
        FlexCell(child: Text('2')),
        FlexCell(child: Text('Jane Smith')),
        FlexCell(child: Text('30')),
      ],
    ),
  ],
);

5. 处理交互

你可以在 FlexCell 中添加交互元素,如按钮或点击事件。

FlexTable(
  columns: [
    FlexColumn(label: 'ID', grow: 1),
    FlexColumn(label: 'Name', grow: 2),
    FlexColumn(label: 'Action', grow: 1),
  ],
  rows: [
    FlexRow(
      cells: [
        FlexCell(child: Text('1')),
        FlexCell(child: Text('John Doe')),
        FlexCell(
          child: ElevatedButton(
            onPressed: () {
              print('Button Pressed');
            },
            child: Text('Edit'),
          ),
        ),
      ],
    ),
    // 更多行...
  ],
);
回到顶部