Flutter可编辑表格插件flutter_editable_table的使用

Flutter可编辑表格插件flutter_editable_table的使用

1. 简介

flutter_editable_table 是一个Flutter插件,用于创建可自定义和可编辑的表格。该插件支持从JSON数据生成表格,并提供了丰富的配置选项,如表头、表体、表尾、添加/删除行等功能。

2. 使用步骤

2.1 添加依赖

pubspec.yaml 文件中添加 flutter_editable_table 依赖:

dependencies:
  flutter_editable_table: any
2.2 导入库

在Dart文件中导入 flutter_editable_table 库:

import 'package:flutter_editable_table/flutter_editable_table.dart';

3. 创建可编辑表格

要创建一个新的可编辑表格,可以使用 EditableTable() 小部件,并提供JSON格式的数据。以下是一个完整的示例代码,展示了如何创建一个可编辑的表格并实现一些常用功能,如添加行、切换编辑模式等。

import 'package:flutter/material.dart';
import 'package:flutter_editable_table/constants.dart';
import 'package:flutter_editable_table/entities/table_entity.dart';
import 'package:flutter_editable_table/flutter_editable_table.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Editable Table',
      builder: (context, child) {
        return GestureDetector(
          onTap: () {
            WidgetsBinding.instance.focusManager.primaryFocus?.unfocus();
          },
          child: child,
        );
      },
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Editable Table'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final _editableTableKey = GlobalKey<EditableTableState>();
  
  // 表格数据
  final data = {
    "column_count": null,
    "row_count": null,
    "addable": true,
    "removable": true,
    "caption": {
      "layout_direction": "row",
      "main_caption": {
        "title": "表格标题",
        "display": true,
        "editable": false,
        "style": {
          "font_weight": "bold",
          "font_size": 18.0,
          "font_color": "#333333",
          "horizontal_alignment": "center",
          "vertical_alignment": "center",
          "text_align": "center"
        }
      },
      "sub_caption": {
        "title": null,
        "display": true,
        "editable": true,
        "input_decoration": {
          "min_lines": 1,
          "max_lines": 1,
          "max_length": 64,
          "hint_text": "请输入副标题",
          "fill_color": null
        },
        "constrains": {"required": true},
        "style": {
          "font_weight": "normal",
          "font_size": 14.0,
          "font_color": "#333333",
          "horizontal_alignment": "center",
          "vertical_alignment": "center",
          "text_align": "center"
        }
      }
    },
    "columns": [
      {
        "primary_key": true,
        "name": "id",
        "type": "int",
        "format": null,
        "description": null,
        "display": false,
        "editable": false,
        "style": {
          "font_weight": "bold",
          "font_size": 14.0,
          "font_color": "#333333",
          "background_color": "#b5cfd2",
          "horizontal_alignment": "center",
          "vertical_alignment": "center",
          "text_align": "center"
        }
      },
      {
        "auto_increase": true,
        "type": "int",
        "format": "Step __VALUE__",
        "description": null,
        "display": true,
        "editable": false,
        "width_factor": 0.2,
        "style": {
          "font_weight": "bold",
          "font_size": 14.0,
          "font_color": "#333333",
          "background_color": "#b5cfd2",
          "horizontal_alignment": "center",
          "vertical_alignment": "center",
          "text_align": "center"
        }
      },
      {
        "name": "name",
        "title": "姓名",
        "type": "string",
        "format": null,
        "description": "用户姓名",
        "display": true,
        "editable": true,
        "width_factor": 0.4,
        "input_decoration": {
          "min_lines": 1,
          "max_lines": 1,
          "max_length": 128,
          "hint_text": "请输入姓名"
        },
        "constrains": {"required": true},
        "style": {
          "font_weight": "bold",
          "font_size": 14.0,
          "font_color": "#333333",
          "background_color": "#b5cfd2",
          "horizontal_alignment": "center",
          "vertical_alignment": "center",
          "text_align": "center"
        }
      },
      {
        "name": "age",
        "title": "年龄",
        "type": "integer",
        "format": null,
        "description": "年龄",
        "display": true,
        "editable": true,
        "width_factor": 0.2,
        "input_decoration": {
          "min_lines": 1,
          "max_lines": 1,
          "max_length": 3,
          "hint_text": "请输入年龄"
        },
        "constrains": {"required": true, "minimum": 1, "maximum": 120},
        "style": {
          "font_weight": "bold",
          "font_size": 14.0,
          "font_color": "#333333",
          "background_color": "#b5cfd2",
          "horizontal_alignment": "center",
          "vertical_alignment": "center",
          "text_align": "center"
        }
      },
      {
        "name": "desc",
        "title": "描述",
        "type": "string",
        "format": null,
        "description": "描述",
        "display": true,
        "editable": true,
        "width_factor": 0.4,
        "input_decoration": {
          "min_lines": 3,
          "max_lines": 5,
          "max_length": 128,
          "hint_text": "请输入描述"
        },
        "constrains": {"required": false, "minimum": 1, "maximum": 100},
        "style": {
          "font_weight": "bold",
          "font_size": 14.0,
          "font_color": "#333333",
          "background_color": "#b5cfd2",
          "horizontal_alignment": "center",
          "vertical_alignment": "center",
          "text_align": "center"
        }
      },
      {
        "name": "salary",
        "title": "工资",
        "type": "float",
        "format": null,
        "description": "工资",
        "display": true,
        "editable": true,
        "width_factor": 0.2,
        "input_decoration": {
          "min_lines": 1,
          "max_lines": 1,
          "max_length": 128,
          "hint_text": "请输入工资"
        },
        "constrains": {"required": true, "minimum": -100, "maximum": 10000},
        "style": {
          "font_weight": "bold",
          "font_size": 14.0,
          "font_color": "#333333",
          "background_color": "#b5cfd2",
          "horizontal_alignment": "center",
          "vertical_alignment": "center",
          "text_align": "center"
        }
      },
      {
        "name": "married",
        "title": "已婚",
        "type": "bool",
        "format": null,
        "description": "是否已婚",
        "display": true,
        "editable": true,
        "width_factor": 0.12,
        "constrains": {"required": false},
        "style": {
          "font_weight": "bold",
          "font_size": 14.0,
          "font_color": "#333333",
          "background_color": "#b5cfd2",
          "horizontal_alignment": "center",
          "vertical_alignment": "center",
          "text_align": "center"
        }
      },
      {
        "name": "d_o_m",
        "title": "结婚日期",
        "type": "date",
        "format": null,
        "description": "结婚日期",
        "display": true,
        "editable": true,
        "width_factor": 0.3,
        "input_decoration": {"hint_text": "请输入结婚日期"},
        "style": {
          "font_weight": "bold",
          "font_size": 14.0,
          "font_color": "#333333",
          "background_color": "#b5cfd2",
          "horizontal_alignment": "center",
          "vertical_alignment": "center",
          "text_align": "center"
        }
      },
      {
        "name": "l_s_t",
        "title": "最后一次购物时间",
        "type": "datetime",
        "format": null,
        "description": "最后一次购物时间",
        "display": true,
        "editable": true,
        "width_factor": 0.5,
        "input_decoration": {
          "hint_text": "请输入最后一次购物时间"
        },
        "constrains": {"required": true},
        "style": {
          "font_weight": "bold",
          "font_size": 14.0,
          "font_color": "#333333",
          "background_color": "#b5cfd2",
          "horizontal_alignment": "center",
          "vertical_alignment": "center",
          "text_align": "center"
        }
      }
    ],
    "rows": [
      {
        "id": 0,
        "name": "Tom",
        "age": 18,
        "desc": "我是Tom",
        "salary": 1000.5,
        "married": false,
        "d_o_m": null,
        "l_s_t": null
      },
      {
        "id": 1,
        "name": "Sam",
        "age": 20,
        "desc": null,
        "salary": 1234.5,
        "married": false,
        "d_o_m": null,
        "l_s_t": "2021-06-23 11:28"
      },
      {
        "id": 2,
        "name": "Olivia",
        "age": 25,
        "desc": null,
        "salary": 2500.0,
        "married": true,
        "d_o_m": "2020-10-01",
        "l_s_t": "2021-01-08 20:20"
      },
      {
        "id": 3,
        "name": "Liam",
        "age": 23,
        "desc": null,
        "salary": 3000.0,
        "married": true,
        "d_o_m": "2018-08-01",
        "l_s_t": "2021-11-11 18:10"
      },
      {
        "id": 4,
        "name": "David",
        "age": 26,
        "desc": null,
        "salary": 2300.0,
        "married": true,
        "d_o_m": "2019-03-05",
        "l_s_t": "2021-12-08 21:30"
      },
    ],
    "footer": {
      "layout_direction": "row",
      "content": [
        {
          "title": "平均年龄: 22.4",
          "display": true,
          "editable": false,
          "style": {
            "font_weight": "normal",
            "font_size": 14.0,
            "font_color": "#333333",
            "horizontal_alignment": "center",
            "vertical_alignment": "center",
            "text_align": "center"
          }
        },
        {
          "title": "已婚人数: 3",
          "display": true,
          "editable": false,
          "style": {
            "font_weight": "normal",
            "font_size": 14.0,
            "font_color": "#333333",
            "horizontal_alignment": "center",
            "vertical_alignment": "center",
            "text_align": "center"
          }
        },
        {
          "title": null,
          "display": true,
          "editable": true,
          "input_decoration": {
            "min_lines": 1,
            "max_lines": 1,
            "max_length": 64,
            "hint_text": "请输入身份",
            "fill_color": null
          },
          "constrains": {"required": true},
          "style": {
            "font_weight": "normal",
            "font_size": 14.0,
            "font_color": "#333333",
            "horizontal_alignment": "center",
            "vertical_alignment": "center",
            "text_align": "center"
          }
        }
      ]
    }
  };

  bool editing = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: IconButton(
          icon: Icon(Icons.print),
          onPressed: () {
            print(_editableTableKey.currentState?.currentData);
          },
        ),
        title: Text(widget.title),
        centerTitle: true,
        actions: [
          GestureDetector(
            behavior: HitTestBehavior.opaque,
            onTap: () {
              WidgetsBinding.instance.focusManager.primaryFocus?.unfocus();
              _editableTableKey.currentState?.addRow();
            },
            child: Icon(Icons.add),
          ),
          SizedBox(width: 8.0),
          GestureDetector(
            behavior: HitTestBehavior.opaque,
            onTap: () {
              WidgetsBinding.instance.focusManager.primaryFocus?.unfocus();
              _editableTableKey.currentState?.readOnly = editing;
              setState(() {
                editing = !editing;
              });
              if (!editing) {
                print(
                    '表格填写状态: ${_editableTableKey.currentState?.isFilled}');
              }
            },
            child: Icon(!editing ? Icons.edit : Icons.check),
          ),
          SizedBox(width: 14.0),
        ],
      ),
      body: SingleChildScrollView(
        child: EditableTable(
          key: _editableTableKey,
          data: data,
          entity: TableEntity.fromJson(data),
          readOnly: true,
          tablePadding: EdgeInsets.all(8.0),
          captionBorder: Border(
            top: BorderSide(color: Color(0xFF999999)),
            left: BorderSide(color: Color(0xFF999999)),
            right: BorderSide(color: Color(0xFF999999)),
          ),
          headerBorder: Border.all(color: Color(0xFF999999)),
          rowBorder: Border.all(color: Color(0xFF999999)),
          footerBorder: Border.all(color: Color(0xFF999999)),
          removeRowIcon: Icon(
            Icons.remove_circle_outline,
            size: 24.0,
            color: Colors.redAccent,
          ),
          addRowIcon: Icon(
            Icons.add_circle_outline,
            size: 24.0,
            color: Colors.white,
          ),
          addRowIconContainerBackgroundColor: Colors.blueAccent,
          formFieldAutoValidateMode: AutovalidateMode.always,
          onRowRemoved: (row) {
            print('行被移除: ${row.toString()}');
          },
          onRowAdded: () {
            print('行被添加');
          },
          onFilling: (FillingArea area, dynamic value) {
            print('正在填写: ${area.toString()}, 值: ${value.toString()}');
          },
          onSubmitted: (FillingArea area, dynamic value) {
            print('提交: ${area.toString()}, 值: ${value.toString()}');
          },
        ),
      ),
    );
  }
}

4. 功能说明

  • 添加行:通过点击右上角的 + 按钮,可以在表格中添加新行。
  • 切换编辑模式:点击编辑图标(铅笔)可以切换表格的编辑模式。在编辑模式下,用户可以修改表格中的内容;点击对勾图标可以保存编辑内容,并检查表格是否已填写完整。
  • 打印表格数据:点击左上角的打印图标,可以将当前表格的数据打印到控制台。
  • 移除行:每行末尾有一个删除按钮,点击可以移除该行。
  • 回调函数
    • onRowRemoved:当某一行被移除时触发。
    • onRowAdded:当新行被添加时触发。
    • onFilling:当用户正在填写某个单元格时触发。
    • onSubmitted:当用户提交某个单元格的内容时触发。

5. 获取表格数据

可以通过 GlobalKey 获取表格的当前数据:

final _editableTableKey = GlobalKey<EditableTableState>();

// 获取当前表格数据
print(_editableTableKey.currentState?.currentData);

6. 动态切换只读模式

可以通过 GlobalKey 动态切换表格的只读模式:

_editableTableKey.currentState?.readOnly = true; // 设置为只读模式
_editableTableKey.currentState?.readOnly = false; // 设置为可编辑模式

7. 检查填写状态

如果表格中有必填字段未填写,isFilled 将返回 false

print(_editableTableKey.currentState?.isFilled);

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

1 回复

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


当然,下面是一个关于如何使用 flutter_editable_table 插件的简单示例代码。这个插件允许你在 Flutter 应用中创建可编辑的表格。

首先,确保你已经在 pubspec.yaml 文件中添加了 flutter_editable_table 依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_editable_table: ^x.y.z  # 请替换为最新版本号

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

接下来,创建一个 Flutter 应用,并在你的主 Dart 文件中使用 flutter_editable_table 插件。以下是一个完整的示例:

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Editable Table Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: EditableTableDemo(),
    );
  }
}

class EditableTableDemo extends StatefulWidget {
  @override
  _EditableTableDemoState createState() => _EditableTableDemoState();
}

class _EditableTableDemoState extends State<EditableTableDemo> {
  final List<List<String>> data = [
    ['Name', 'Age', 'Email'],
    ['Alice', '30', 'alice@example.com'],
    ['Bob', '25', 'bob@example.com'],
    ['Charlie', '35', 'charlie@example.com'],
  ];

  final List<String> headers = ['Name', 'Age', 'Email'];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Editable Table Demo'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: EditableTable(
          headers: headers,
          rows: data,
          onCellSubmitted: (row, col, newValue) {
            setState(() {
              data[row][col] = newValue;
            });
          },
          cellDecoration: BoxDecoration(
            border: Border(
              bottom: BorderSide(color: Colors.grey[300]!),
            ),
          ),
          headerDecoration: BoxDecoration(
            backgroundColor: Colors.grey[200],
          ),
          cellTextStyle: TextStyle(fontSize: 18),
          headerTextStyle: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
          padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
        ),
      ),
    );
  }
}

代码解释:

  1. 依赖导入:导入 flutterflutter_editable_table 包。
  2. 应用入口:定义 MyApp 类作为应用的入口,并设置主题和主页。
  3. 主页:创建 EditableTableDemo 类,它是一个有状态的组件,用于管理表格数据的状态。
  4. 数据定义:定义一个 data 列表,其中每个子列表代表表格的一行数据。headers 列表定义表格的列头。
  5. 构建 UI:在 build 方法中,使用 ScaffoldPadding 组件来布局,并在中间放置 EditableTable 组件。
  6. EditableTable 参数
    • headers:表格的列头。
    • rows:表格的数据行。
    • onCellSubmitted:单元格编辑完成后的回调函数,用于更新数据。
    • cellDecorationheaderDecoration:单元格和列头的装饰,如边框和背景颜色。
    • cellTextStyleheaderTextStyle:单元格和列头的文本样式。
    • padding:单元格的内边距。

这个示例展示了如何使用 flutter_editable_table 插件来创建一个简单的可编辑表格,并处理用户输入来更新表格数据。你可以根据需要进一步自定义表格的样式和功能。

回到顶部