Flutter学习记录——12.表格组件

1.Table Widget

我们先看下表格绘制的第一种实现组件:Table。Table 的继承关系:

Table -> RenderObjectWidget -> Widget

Table 中的每一行用 TableRow 组件,列数用 columnWidths 属性控制。

我们看下 Table 的构造方法:

Table({
    Key key,
    // 每行的TableRow集合
    this.children = const <TableRow>[],
    // 设置每列的宽度
    this.columnWidths,
    // 默认每列宽度值,默认情况下均分
    this.defaultColumnWidth = const FlexColumnWidth(1.0),
    // 文字方向
    this.textDirection,
    // 表格边框设置
    this.border,
    // 默认垂直方向的对齐方式
    this.defaultVerticalAlignment = TableCellVerticalAlignment.top,
    // defaultVerticalAlignment为baseline的时候,配置生效
    this.textBaseline,
  })

通过实例来学习 Table 的用法:

class TableSamplesState extends State<TableSamples> {
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text('Table Demo'), primary: true),
        body: Padding(
          padding: EdgeInsets.all(10),
          // 使用Table绘制表格
          child: Table(
            // 有很多种设置宽度方式
            columnWidths: {
              ///固定列宽度
              0: FixedColumnWidth(50),

              ///弹性列宽度
              1: FlexColumnWidth(1),

              ///宽度占所在容器的百分比(0-1)
              2: FractionColumnWidth(0.5),
              3: IntrinsicColumnWidth(flex: 0.2),
              4: MaxColumnWidth(
                  FixedColumnWidth(100.0), FractionColumnWidth(0.1)),

              ///大于容器10%宽度,但小于等于100px
              5: MinColumnWidth(
                  FixedColumnWidth(100.0), FractionColumnWidth(0.1)),
            },
            // 设置表格边框
            border: TableBorder.all(color: Colors.black, width: 1),
            children: <TableRow>[
              // 每行内容设置
              TableRow(children: <Widget>[
                // 每个表格单元
                TableCell(
                  verticalAlignment: TableCellVerticalAlignment.middle,
                  child: Center(
                    child: Text(
                      'Title1',
                      style:
                          TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
                    ),
                  ),
                ),
                TableCell(
                  verticalAlignment: TableCellVerticalAlignment.middle,
                  child: Center(
                    child: Text(
                      'Title2',
                      style:
                          TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
                    ),
                  ),
                ),
                TableCell(
                  verticalAlignment: TableCellVerticalAlignment.middle,
                  child: Center(
                    child: Text(
                      'Title3',
                      style:
                          TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
                    ),
                  ),
                ),
              ]),
              TableRow(children: <Widget>[
                TableCell(
                  child: Text('data1'),
                ),
                TableCell(
                  child: Text('data2'),
                ),
                TableCell(
                  child: Text('data3'),
                ),
              ]),
              TableRow(children: <Widget>[
                TableCell(
                  child: Text('data1'),
                ),
                TableCell(
                  child: Text('data2'),
                ),
                TableCell(
                  child: Text('data3'),
                ),
              ]),
              TableRow(children: <Widget>[
                TableCell(
                  child: Text('data1'),
                ),
                TableCell(
                  child: Text('data2'),
                ),
                TableCell(
                  child: Text('data3'),
                ),
              ]),
              TableRow(children: <Widget>[
                TableCell(
                  child: Text('data1'),
                ),
                TableCell(
                  child: Text('data2'),
                ),
                TableCell(
                  child: Text('data3'),
                ),
              ]),
            ],
          ),
        ));
  }
}

运行效果如图:

Table

可见,Table 的用法很简单。

2.DataTable Widget

下面我们学习一下绘制表格的另一个组件:DataTable,这个功能更加强大,比较常用。

扫描二维码关注公众号,回复: 8859472 查看本文章

DataTable 继承自 StatelessWidget,是一个无状态组件。

我们看下 DataTable 的构造方法:

DataTable({
    Key key,
    // 设置表头
    @required this.columns,
    // 列排序索引
    this.sortColumnIndex,
    // 是否升序排序,默认为升序
    this.sortAscending = true,
    // 点击全选
    this.onSelectAll,
    // 表格每行内容
    @required this.rows,
  })

在 DataTable 中 columns 属性里放置的是 DataColumn 来设置列属性,我们看下 DataColumn 的构造方法:

const DataColumn({
    // 标签,可使用文本或者尺寸为18的图标
    @required this.label,
    // 工具提示
    this.tooltip,
    // 是否包含数字
    this.numeric = false,
    // 排序时调用
    this.onSort,
  })

在 DataTable 中 rows 属性里放置的是 DataRow 来设置行内容和属性,我们看下 DataRow 的构造方法:

const DataRow({
    this.key,
    // 是否选中
    this.selected = false,
    // 选中状态改变时回调
    this.onSelectChanged,
    // 子表格单元
    @required this.cells,
  })

这里的每个子表格单元使用的是 DataCell 来设置内容和属性,看看 DataCell 的构造方法:

const DataCell(
    // 子控件,一般为Text或DropdownButton
    this.child, {
    // 是否为占位符,若子控件为Text,显示占位符文本样式
    this.placeholder = false,
    // 是否显示编辑图标,配合onTab使用
    this.showEditIcon = false,
    // 点击回调
    this.onTap,
  })

接下来我们通过一个实例来看下 DataTable 的用法:

class DataTableState extends State<DataTableSamples> {
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text('DataTable Demo'), primary: true),
        body: DataTable(
          // 行
          rows: <DataRow>[
            // 每行内容设置
            DataRow(
              cells: <DataCell>[
                // 子表格单元
                DataCell(Text('data1'), onTap: onTap),
                DataCell(Text('data2'), onTap: onTap),
                DataCell(Text('data3'), onTap: onTap),
              ],
            ),
            DataRow(
              cells: <DataCell>[
                DataCell(Text('data1'), onTap: onTap),
                DataCell(Text('data2'), onTap: onTap),
                DataCell(Text('data3'), onTap: onTap),
              ],
            ),
            DataRow(
              cells: <DataCell>[
                DataCell(Text('data1'), onTap: onTap),
                DataCell(Text('data2'), onTap: onTap),
                DataCell(Text('data3'), onTap: onTap),
              ],
            ),
            DataRow(
              cells: <DataCell>[
                DataCell(Text('data1'), onTap: onTap),
                DataCell(Text('data2'), onTap: onTap),
                DataCell(Text('data3'), onTap: onTap),
              ],
            ),
            DataRow(
              cells: <DataCell>[
                DataCell(Text('data1'), onTap: onTap),
                DataCell(Text('data2'), onTap: onTap),
                DataCell(Text('data3'), onTap: onTap),
              ],
            ),
          ],

          // 列
          columns: <DataColumn>[
            DataColumn(label: Text('DataColumn1')),
            DataColumn(label: Text('DataColumn2')),
            DataColumn(label: Text('DataColumn3')),
          ],
        ));
  }
}

void onTap() {
  print('data onTap');
}

运行效果如图:

avatar

3.PaginatedDataTable Widget

这里拓展一下,PaginatedDataTable 也是一个 DataTable,主要用来绘制有分页类型的表格。

PaginatedDataTable 继承自 StatefulWidget,是一个有状态组件。

PaginatedDataTable 的构造方法如下:

PaginatedDataTable({
    Key key,
    // 表名,通常为Text,也可以是ButtonBar/FlatButton
    @required this.header,
    // 动作,List<Widget>集合,内部子控件大小宽高要24.0,padding为8.0
    this.actions,
    // 列集合
    @required this.columns,
    // 列排序索引
    this.sortColumnIndex,
    // 是否升序排序
    this.sortAscending = true,
    // 点击全选回调
    this.onSelectAll,
    // 初始索引
    this.initialFirstRowIndex = 0,
    // 页数更改监听,左右箭头点击时
    this.onPageChanged,
    // 默认一页显示的行数,默认为10
    this.rowsPerPage = defaultRowsPerPage,
    // 可选择页数
    this.availableRowsPerPage = const <int>[defaultRowsPerPage, defaultRowsPerPage * 2, defaultRowsPerPage * 5, defaultRowsPerPage * 10],
    // 点击可选择页数下拉监听
    this.onRowsPerPageChanged,
    this.dragStartBehavior = DragStartBehavior.down,
    // 表格数据源DataTableSource
    @required this.source
  })

PaginatedDataTable 在使用时,外层要是一个 ListView 或 ScrollView 这种可滚动容器才可以使用。

在使用 PaginatedDataTable 时,最重要的一个不同就是要设置 DataTableSource,我们需要编写提供一个 DataTableSource 表格数据源提供给表格数据。

PaginatedDataTable 的用法实例:

class PaginatedDataTableState extends State<PaginatedDataTableSamples> {
  TableDataSource _dataSource = TableDataSource();
  int _defalutRowPageCount = 8;
  int _sortColumnIndex;
  bool _sortAscending = true;

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text('PaginatedDataTable Demo'), primary: true),
        // 外层用ListView包裹
        body: ListView(
          padding: EdgeInsets.all(10),
          children: <Widget>[
            // PaginatedDataTable
            PaginatedDataTable(
              // 表格数据源
              source: _dataSource,
              // 默认为0
              initialFirstRowIndex: 0,
              // 全选操作
              onSelectAll: (bool checked) {
                _dataSource.selectAll(checked);
              },
              // 每页显示的行数
              rowsPerPage: _defalutRowPageCount,
              // 每页显示数量改变后的回调
              onRowsPerPageChanged: (value) {
                setState(() {
                  _defalutRowPageCount = value;
                });
              },
              // 设置每页可以显示的行数值列表选项
              availableRowsPerPage: [5, 8],
              // 翻页操作回调
              onPageChanged: (value) {
                print('$value');
              },
              // 是否升序排序
              sortAscending: _sortAscending,
              sortColumnIndex: _sortColumnIndex,
              // 表格头部
              header: Text('Data Header'),
              // 列
              columns: <DataColumn>[
                DataColumn(label: Text('名字')),
                DataColumn(
                    label: Text('价格'),
                    // 加入排序操作
                    onSort: (int columnIndex, bool ascending) {
                      _sort<num>((Shop p) => p.price, columnIndex, ascending);
                    }),
                DataColumn(label: Text('类型')),
              ],
            ),
          ],
        ));
  }

  //排序关联_sortColumnIndex,_sortAscending
  void _sort<T>(Comparable<T> getField(Shop s), int index, bool b) {
    _dataSource._sort(getField, b);
    setState(() {
      this._sortColumnIndex = index;
      this._sortAscending = b;
    });
  }
}

class Shop {
  final String name;
  final int price;
  final String type;

  // 默认为未选中
  bool selected = false;
  Shop(this.name, this.price, this.type);
}

class TableDataSource extends DataTableSource {
  final List<Shop> shops = <Shop>[
    Shop('name', 100, '家电'),
    Shop('name2', 130, '手机'),
    Shop('三星', 130, '手机'),
    Shop('三星', 130, '手机'),
    Shop('三星', 130, '手机'),
    Shop('海信', 100, '家电'),
    Shop('TCL', 100, '家电'),
  ];
  int _selectedCount = 0;

  ///根据位置获取内容行
  @override
  DataRow getRow(int index) {
    Shop shop = shops.elementAt(index);
    return DataRow.byIndex(
        cells: <DataCell>[
          DataCell(
            Text('${shop.name}'),
            placeholder: true,
          ),
          DataCell(Text('${shop.price}'), showEditIcon: true),
          DataCell(Text('${shop.type}'), showEditIcon: false),
        ],
        selected: shop.selected,
        index: index,
        onSelectChanged: (bool isSelected) {
          if (shop.selected != isSelected) {
            _selectedCount += isSelected ? 1 : -1;
            shop.selected = isSelected;
            notifyListeners();
          }
        });
  }

  @override

  ///行数是否不确定
  bool get isRowCountApproximate => false;

  @override

  ///行数
  int get rowCount => shops.length;

  @override

  ///选中的行数
  int get selectedRowCount => _selectedCount;

  void selectAll(bool checked) {
    for (Shop shop in shops) {
      shop.selected = checked;
    }
    _selectedCount = checked ? shops.length : 0;
    notifyListeners();
  }

  //排序,
  void _sort<T>(Comparable<T> getField(Shop shop), bool b) {
    shops.sort((Shop s1, Shop s2) {
      if (!b) {
        //两个项进行交换
        final Shop temp = s1;
        s1 = s2;
        s2 = temp;
      }
      final Comparable<T> s1Value = getField(s1);
      final Comparable<T> s2Value = getField(s2);
      return Comparable.compare(s1Value, s2Value);
    });
    notifyListeners();
  }
}

void onTap() {
  print('data onTap');
}

运行效果如图:

avatar

4.总结

本节博客主要是给大家讲解了 Flutter 的表格绘制组件的用法和特点。

  • 重点掌握 DataTable 和 PaginatedDataTable 的用法。
  • 实践一下这几个 Widget 使用方法,尝试写一个课程表表格页面。
发布了253 篇原创文章 · 获赞 52 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_41151659/article/details/103384781
今日推荐