我已经使用DataTable
在Flutter Dart上建立了一个表格。该表非常大,我同时使用“垂直”和“水平”滚动。
滚动时,我失去对列的引用,我需要知道什么是列。
例如。在屏幕快照上,除非滚动到顶部,否则我不知道数字20.0
和25.0
的含义。
我添加了我要实现的GIF示例。 (使用LibreOffice)。我需要固定的列名(第一行)。
我的表的代码示例:
return SingleChildScrollView(
scrollDirection: Axis.vertical,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: DataTable(
columns: MyDataSet.getColumns(),
rows: widget._data.map<DataRow>((row) => DataRow(
onSelectChanged: (d) {
setState(() {
selectedRow = d ? row.hashCode : null;
});
},
selected: row.hashCode == selectedRow,
cells: MyDataSet.toDataCells(row)
)).toList()
)
),
);
缺少代码示例:
return columns.map<DataColumn>((name) => DataColumn(
label: Text(name, style: TextStyle(fontWeight: FontWeight.bold, color: Colors.black),)
)).toList();
如果标题名称与单元格内容的大小相同,则当前代码运行良好。否则,两个大小将不同。
答案 0 :(得分:4)
几个月前,我遇到了类似的问题,库存 DataTable 和 PaginatedDataTable2 小部件的功能有限,无法修复标题。最终我把这些小部件 appart 并创建了我自己的版本,但有二十一点和固定的标题行。这是 pub.dev 上的插件: https://pub.dev/packages/data_table_2
DataTable2 和 PaginatedDataTable2 类提供与原始版本完全相同的 API。
注意:这些只实现了顶部的粘性行,最左边的列不是固定/粘性的
答案 1 :(得分:2)
我可以使用滚动控制器想出一种解决方法,如下所示:Video
基本上,第一行是水平滚动,第一列是垂直滚动,子表是水平和垂直混合滚动。然后,当您移动子表时,其控制器将移动列和行。
这是一个自定义小部件,其中包含如何使用它的示例:
final _rowsCells = [
[7, 8, 10, 8, 7],
[10, 10, 9, 6, 6],
[5, 4, 5, 7, 5],
[9, 4, 1, 7, 8],
[7, 8, 10, 8, 7],
[10, 10, 9, 6, 6],
[5, 4, 5, 7, 5],
[9, 4, 1, 7, 8],
[7, 8, 10, 8, 7],
[10, 10, 9, 6, 6],
[5, 4, 5, 7, 5],
[9, 4, 1, 7, 8],
[7, 8, 10, 8, 7],
[10, 10, 9, 6, 6],
[5, 4, 5, 7, 5],
[9, 4, 1, 7, 8]
];
final _fixedColCells = [
"Pablo",
"Gustavo",
"John",
"Jack",
"Pablo",
"Gustavo",
"John",
"Jack",
"Pablo",
"Gustavo",
"John",
"Jack",
"Pablo",
"Gustavo",
"John",
"Jack",
];
final _fixedRowCells = [
"Math",
"Informatics",
"Geography",
"Physics",
"Biology"
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: CustomDataTable(
rowsCells: _rowsCells,
fixedColCells: _fixedColCells,
fixedRowCells: _fixedRowCells,
cellBuilder: (data) {
return Text('$data', style: TextStyle(color: Colors.red));
},
),
);
}
class CustomDataTable<T> extends StatefulWidget {
final T fixedCornerCell;
final List<T> fixedColCells;
final List<T> fixedRowCells;
final List<List<T>> rowsCells;
final Widget Function(T data) cellBuilder;
final double fixedColWidth;
final double cellWidth;
final double cellHeight;
final double cellMargin;
final double cellSpacing;
CustomDataTable({
this.fixedCornerCell,
this.fixedColCells,
this.fixedRowCells,
@required this.rowsCells,
this.cellBuilder,
this.fixedColWidth = 60.0,
this.cellHeight = 56.0,
this.cellWidth = 120.0,
this.cellMargin = 10.0,
this.cellSpacing = 10.0,
});
@override
State<StatefulWidget> createState() => CustomDataTableState();
}
class CustomDataTableState<T> extends State<CustomDataTable<T>> {
final _columnController = ScrollController();
final _rowController = ScrollController();
final _subTableYController = ScrollController();
final _subTableXController = ScrollController();
Widget _buildChild(double width, T data) => SizedBox(
width: width, child: widget.cellBuilder?.call(data) ?? Text('$data'));
Widget _buildFixedCol() => widget.fixedColCells == null
? SizedBox.shrink()
: Material(
color: Colors.lightBlueAccent,
child: DataTable(
horizontalMargin: widget.cellMargin,
columnSpacing: widget.cellSpacing,
headingRowHeight: widget.cellHeight,
dataRowHeight: widget.cellHeight,
columns: [
DataColumn(
label: _buildChild(
widget.fixedColWidth, widget.fixedColCells.first))
],
rows: widget.fixedColCells
.sublist(widget.fixedRowCells == null ? 1 : 0)
.map((c) => DataRow(
cells: [DataCell(_buildChild(widget.fixedColWidth, c))]))
.toList()),
);
Widget _buildFixedRow() => widget.fixedRowCells == null
? SizedBox.shrink()
: Material(
color: Colors.greenAccent,
child: DataTable(
horizontalMargin: widget.cellMargin,
columnSpacing: widget.cellSpacing,
headingRowHeight: widget.cellHeight,
dataRowHeight: widget.cellHeight,
columns: widget.fixedRowCells
.map((c) =>
DataColumn(label: _buildChild(widget.cellWidth, c)))
.toList(),
rows: []),
);
Widget _buildSubTable() => Material(
color: Colors.lightGreenAccent,
child: DataTable(
horizontalMargin: widget.cellMargin,
columnSpacing: widget.cellSpacing,
headingRowHeight: widget.cellHeight,
dataRowHeight: widget.cellHeight,
columns: widget.rowsCells.first
.map((c) => DataColumn(label: _buildChild(widget.cellWidth, c)))
.toList(),
rows: widget.rowsCells
.sublist(widget.fixedRowCells == null ? 1 : 0)
.map((row) => DataRow(
cells: row
.map((c) => DataCell(_buildChild(widget.cellWidth, c)))
.toList()))
.toList()));
Widget _buildCornerCell() =>
widget.fixedColCells == null || widget.fixedRowCells == null
? SizedBox.shrink()
: Material(
color: Colors.amberAccent,
child: DataTable(
horizontalMargin: widget.cellMargin,
columnSpacing: widget.cellSpacing,
headingRowHeight: widget.cellHeight,
dataRowHeight: widget.cellHeight,
columns: [
DataColumn(
label: _buildChild(
widget.fixedColWidth, widget.fixedCornerCell))
],
rows: []),
);
@override
void initState() {
super.initState();
_subTableXController.addListener(() {
_rowController.jumpTo(_subTableXController.position.pixels);
});
_subTableYController.addListener(() {
_columnController.jumpTo(_subTableYController.position.pixels);
});
}
@override
Widget build(BuildContext context) {
return Stack(
children: <Widget>[
Row(
children: <Widget>[
SingleChildScrollView(
controller: _columnController,
scrollDirection: Axis.vertical,
physics: NeverScrollableScrollPhysics(),
child: _buildFixedCol(),
),
Flexible(
child: SingleChildScrollView(
controller: _subTableXController,
scrollDirection: Axis.horizontal,
child: SingleChildScrollView(
controller: _subTableYController,
scrollDirection: Axis.vertical,
child: _buildSubTable(),
),
),
),
],
),
Row(
children: <Widget>[
_buildCornerCell(),
Flexible(
child: SingleChildScrollView(
controller: _rowController,
scrollDirection: Axis.horizontal,
physics: NeverScrollableScrollPhysics(),
child: _buildFixedRow(),
),
),
],
),
],
);
}
}
由于第一列,第一行和子表是独立的,因此我必须为每个表创建一个DataTable
。而且由于DataTable
具有无法删除的标题,因此第一行和子表的标题被第一行隐藏。
此外,我还必须使第一列和第一行不可手动滚动,因为如果滚动它们,子表将不会滚动。
这可能不是最佳解决方案,但目前看来并不是另一种解决方案。您可以尝试改进这种方法,也许使用Table
或其他小部件代替DataTable
,至少可以避免隐藏子表和第一列的标题。
答案 2 :(得分:2)
试试flutter包horizontal_data_table
一个 Flutter Widget,它创建一个水平表格,左侧固定列。
dependencies:
horizontal_data_table: ^2.5.0