Flutter学习记录——12.表格组件
文章目录
- 1.Table Widget
- 2.DataTable Widget
- 3.PaginatedDataTable Widget
- 4.总结
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,这个功能更加强大,比较常用。
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');
}
运行效果如图:
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');
}
运行效果如图:
4.总结
本节博客主要是给大家讲解了 Flutter 的表格绘制组件的用法和特点。
- 重点掌握 DataTable 和 PaginatedDataTable 的用法。
- 实践一下这几个 Widget 使用方法,尝试写一个课程表表格页面。
还没有评论,来说两句吧...