Custom height parameters for DataTable header and data rows (#33535)
* Custom dataRowHeight for DataTable and PaginatedDataTable * Custom headingRowHeight for DataTable and PaginatedDataTable
This commit is contained in:
parent
23c25d9e2d
commit
71254a6147
@ -262,6 +262,8 @@ class DataTable extends StatelessWidget {
|
|||||||
this.sortColumnIndex,
|
this.sortColumnIndex,
|
||||||
this.sortAscending = true,
|
this.sortAscending = true,
|
||||||
this.onSelectAll,
|
this.onSelectAll,
|
||||||
|
this.dataRowHeight = 48.0,
|
||||||
|
this.headingRowHeight = 56.0,
|
||||||
this.horizontalMargin = 24.0,
|
this.horizontalMargin = 24.0,
|
||||||
this.columnSpacing = 56.0,
|
this.columnSpacing = 56.0,
|
||||||
@required this.rows,
|
@required this.rows,
|
||||||
@ -269,6 +271,8 @@ class DataTable extends StatelessWidget {
|
|||||||
assert(columns.isNotEmpty),
|
assert(columns.isNotEmpty),
|
||||||
assert(sortColumnIndex == null || (sortColumnIndex >= 0 && sortColumnIndex < columns.length)),
|
assert(sortColumnIndex == null || (sortColumnIndex >= 0 && sortColumnIndex < columns.length)),
|
||||||
assert(sortAscending != null),
|
assert(sortAscending != null),
|
||||||
|
assert(dataRowHeight != null),
|
||||||
|
assert(headingRowHeight != null),
|
||||||
assert(horizontalMargin != null),
|
assert(horizontalMargin != null),
|
||||||
assert(columnSpacing != null),
|
assert(columnSpacing != null),
|
||||||
assert(rows != null),
|
assert(rows != null),
|
||||||
@ -315,6 +319,16 @@ class DataTable extends StatelessWidget {
|
|||||||
/// row is selectable.
|
/// row is selectable.
|
||||||
final ValueSetter<bool> onSelectAll;
|
final ValueSetter<bool> onSelectAll;
|
||||||
|
|
||||||
|
/// The height of each row (excluding the row that contains column headings).
|
||||||
|
///
|
||||||
|
/// This value defaults to 48.0 to adhere to the Material Design specifications.
|
||||||
|
final double dataRowHeight;
|
||||||
|
|
||||||
|
/// The height of the heading row.
|
||||||
|
///
|
||||||
|
/// This value defaults to 56.0 to adhere to the Material Design specifications.
|
||||||
|
final double headingRowHeight;
|
||||||
|
|
||||||
/// The horizontal margin between the edges of the table and the content
|
/// The horizontal margin between the edges of the table and the content
|
||||||
/// in the first and last cells of each row.
|
/// in the first and last cells of each row.
|
||||||
///
|
///
|
||||||
@ -330,7 +344,9 @@ class DataTable extends StatelessWidget {
|
|||||||
final double columnSpacing;
|
final double columnSpacing;
|
||||||
|
|
||||||
/// The data to show in each row (excluding the row that contains
|
/// The data to show in each row (excluding the row that contains
|
||||||
/// the column headings). Must be non-null, but may be empty.
|
/// the column headings).
|
||||||
|
///
|
||||||
|
/// Must be non-null, but may be empty.
|
||||||
final List<DataRow> rows;
|
final List<DataRow> rows;
|
||||||
|
|
||||||
// Set by the constructor to the index of the only Column that is
|
// Set by the constructor to the index of the only Column that is
|
||||||
@ -367,8 +383,6 @@ class DataTable extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const double _headingRowHeight = 56.0;
|
|
||||||
static const double _dataRowHeight = 48.0;
|
|
||||||
static const double _sortArrowPadding = 2.0;
|
static const double _sortArrowPadding = 2.0;
|
||||||
static const double _headingFontSize = 12.0;
|
static const double _headingFontSize = 12.0;
|
||||||
static const Duration _sortArrowAnimationDuration = Duration(milliseconds: 150);
|
static const Duration _sortArrowAnimationDuration = Duration(milliseconds: 150);
|
||||||
@ -430,14 +444,14 @@ class DataTable extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
label = Container(
|
label = Container(
|
||||||
padding: padding,
|
padding: padding,
|
||||||
height: _headingRowHeight,
|
height: headingRowHeight,
|
||||||
alignment: numeric ? Alignment.centerRight : AlignmentDirectional.centerStart,
|
alignment: numeric ? Alignment.centerRight : AlignmentDirectional.centerStart,
|
||||||
child: AnimatedDefaultTextStyle(
|
child: AnimatedDefaultTextStyle(
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
// TODO(ianh): font family should match Theme; see https://github.com/flutter/flutter/issues/3116
|
// TODO(ianh): font family should match Theme; see https://github.com/flutter/flutter/issues/3116
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
fontSize: _headingFontSize,
|
fontSize: _headingFontSize,
|
||||||
height: math.min(1.0, _headingRowHeight / _headingFontSize),
|
height: math.min(1.0, headingRowHeight / _headingFontSize),
|
||||||
color: (Theme.of(context).brightness == Brightness.light)
|
color: (Theme.of(context).brightness == Brightness.light)
|
||||||
? ((onSort != null && sorted) ? Colors.black87 : Colors.black54)
|
? ((onSort != null && sorted) ? Colors.black87 : Colors.black54)
|
||||||
: ((onSort != null && sorted) ? Colors.white : Colors.white70),
|
: ((onSort != null && sorted) ? Colors.white : Colors.white70),
|
||||||
@ -483,7 +497,7 @@ class DataTable extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
label = Container(
|
label = Container(
|
||||||
padding: padding,
|
padding: padding,
|
||||||
height: _dataRowHeight,
|
height: dataRowHeight,
|
||||||
alignment: numeric ? Alignment.centerRight : AlignmentDirectional.centerStart,
|
alignment: numeric ? Alignment.centerRight : AlignmentDirectional.centerStart,
|
||||||
child: DefaultTextStyle(
|
child: DefaultTextStyle(
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
|
@ -70,6 +70,8 @@ class PaginatedDataTable extends StatefulWidget {
|
|||||||
this.sortColumnIndex,
|
this.sortColumnIndex,
|
||||||
this.sortAscending = true,
|
this.sortAscending = true,
|
||||||
this.onSelectAll,
|
this.onSelectAll,
|
||||||
|
this.dataRowHeight = 48.0,
|
||||||
|
this.headingRowHeight = 56.0,
|
||||||
this.horizontalMargin = 24.0,
|
this.horizontalMargin = 24.0,
|
||||||
this.columnSpacing = 56.0,
|
this.columnSpacing = 56.0,
|
||||||
this.initialFirstRowIndex = 0,
|
this.initialFirstRowIndex = 0,
|
||||||
@ -85,6 +87,8 @@ class PaginatedDataTable extends StatefulWidget {
|
|||||||
assert(columns.isNotEmpty),
|
assert(columns.isNotEmpty),
|
||||||
assert(sortColumnIndex == null || (sortColumnIndex >= 0 && sortColumnIndex < columns.length)),
|
assert(sortColumnIndex == null || (sortColumnIndex >= 0 && sortColumnIndex < columns.length)),
|
||||||
assert(sortAscending != null),
|
assert(sortAscending != null),
|
||||||
|
assert(dataRowHeight != null),
|
||||||
|
assert(headingRowHeight != null),
|
||||||
assert(horizontalMargin != null),
|
assert(horizontalMargin != null),
|
||||||
assert(columnSpacing != null),
|
assert(columnSpacing != null),
|
||||||
assert(rowsPerPage != null),
|
assert(rowsPerPage != null),
|
||||||
@ -135,6 +139,16 @@ class PaginatedDataTable extends StatefulWidget {
|
|||||||
/// See [DataTable.onSelectAll].
|
/// See [DataTable.onSelectAll].
|
||||||
final ValueSetter<bool> onSelectAll;
|
final ValueSetter<bool> onSelectAll;
|
||||||
|
|
||||||
|
/// The height of each row (excluding the row that contains column headings).
|
||||||
|
///
|
||||||
|
/// This value is optional and defaults to 48.0 if not specified.
|
||||||
|
final double dataRowHeight;
|
||||||
|
|
||||||
|
/// The height of the heading row.
|
||||||
|
///
|
||||||
|
/// This value is optional and defaults to 56.0 if not specified.
|
||||||
|
final double headingRowHeight;
|
||||||
|
|
||||||
/// The horizontal margin between the edges of the table and the content
|
/// The horizontal margin between the edges of the table and the content
|
||||||
/// in the first and last cells of each row.
|
/// in the first and last cells of each row.
|
||||||
///
|
///
|
||||||
@ -448,6 +462,8 @@ class PaginatedDataTableState extends State<PaginatedDataTable> {
|
|||||||
sortColumnIndex: widget.sortColumnIndex,
|
sortColumnIndex: widget.sortColumnIndex,
|
||||||
sortAscending: widget.sortAscending,
|
sortAscending: widget.sortAscending,
|
||||||
onSelectAll: widget.onSelectAll,
|
onSelectAll: widget.onSelectAll,
|
||||||
|
dataRowHeight: widget.dataRowHeight,
|
||||||
|
headingRowHeight: widget.headingRowHeight,
|
||||||
horizontalMargin: widget.horizontalMargin,
|
horizontalMargin: widget.horizontalMargin,
|
||||||
columnSpacing: widget.columnSpacing,
|
columnSpacing: widget.columnSpacing,
|
||||||
rows: _getRows(_firstRowIndex, widget.rowsPerPage),
|
rows: _getRows(_firstRowIndex, widget.rowsPerPage),
|
||||||
|
@ -267,6 +267,123 @@ void main() {
|
|||||||
expect(tester.takeException(), isNull);
|
expect(tester.takeException(), isNull);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('DataTable custom row height', (WidgetTester tester) async {
|
||||||
|
Widget buildCustomTable({
|
||||||
|
int sortColumnIndex,
|
||||||
|
bool sortAscending = true,
|
||||||
|
double dataRowHeight = 48.0,
|
||||||
|
double headingRowHeight = 56.0,
|
||||||
|
}) {
|
||||||
|
return DataTable(
|
||||||
|
sortColumnIndex: sortColumnIndex,
|
||||||
|
sortAscending: sortAscending,
|
||||||
|
onSelectAll: (bool value) {},
|
||||||
|
dataRowHeight: dataRowHeight,
|
||||||
|
headingRowHeight: headingRowHeight,
|
||||||
|
columns: <DataColumn>[
|
||||||
|
const DataColumn(
|
||||||
|
label: Text('Name'),
|
||||||
|
tooltip: 'Name',
|
||||||
|
),
|
||||||
|
DataColumn(
|
||||||
|
label: const Text('Calories'),
|
||||||
|
tooltip: 'Calories',
|
||||||
|
numeric: true,
|
||||||
|
onSort: (int columnIndex, bool ascending) {},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
rows: kDesserts.map<DataRow>((Dessert dessert) {
|
||||||
|
return DataRow(
|
||||||
|
key: Key(dessert.name),
|
||||||
|
onSelectChanged: (bool selected) {},
|
||||||
|
cells: <DataCell>[
|
||||||
|
DataCell(
|
||||||
|
Text(dessert.name),
|
||||||
|
),
|
||||||
|
DataCell(
|
||||||
|
Text('${dessert.calories}'),
|
||||||
|
showEditIcon: true,
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEFAULT VALUES
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: Material(
|
||||||
|
child: DataTable(
|
||||||
|
onSelectAll: (bool value) {},
|
||||||
|
columns: <DataColumn>[
|
||||||
|
const DataColumn(
|
||||||
|
label: Text('Name'),
|
||||||
|
tooltip: 'Name',
|
||||||
|
),
|
||||||
|
DataColumn(
|
||||||
|
label: const Text('Calories'),
|
||||||
|
tooltip: 'Calories',
|
||||||
|
numeric: true,
|
||||||
|
onSort: (int columnIndex, bool ascending) {},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
rows: kDesserts.map<DataRow>((Dessert dessert) {
|
||||||
|
return DataRow(
|
||||||
|
key: Key(dessert.name),
|
||||||
|
onSelectChanged: (bool selected) {},
|
||||||
|
cells: <DataCell>[
|
||||||
|
DataCell(
|
||||||
|
Text(dessert.name),
|
||||||
|
),
|
||||||
|
DataCell(
|
||||||
|
Text('${dessert.calories}'),
|
||||||
|
showEditIcon: true,
|
||||||
|
onTap: () {},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
expect(tester.renderObject<RenderBox>(
|
||||||
|
find.widgetWithText(Container, 'Name')
|
||||||
|
).size.height, 56.0); // This is the header row height
|
||||||
|
expect(tester.renderObject<RenderBox>(
|
||||||
|
find.widgetWithText(Container, 'Frozen yogurt')
|
||||||
|
).size.height, 48.0); // This is the data row height
|
||||||
|
|
||||||
|
// CUSTOM VALUES
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: Material(child: buildCustomTable(headingRowHeight: 48.0)),
|
||||||
|
));
|
||||||
|
expect(tester.renderObject<RenderBox>(
|
||||||
|
find.widgetWithText(Container, 'Name')
|
||||||
|
).size.height, 48.0);
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: Material(child: buildCustomTable(headingRowHeight: 64.0)),
|
||||||
|
));
|
||||||
|
expect(tester.renderObject<RenderBox>(
|
||||||
|
find.widgetWithText(Container, 'Name')
|
||||||
|
).size.height, 64.0);
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: Material(child: buildCustomTable(dataRowHeight: 30.0)),
|
||||||
|
));
|
||||||
|
expect(tester.renderObject<RenderBox>(
|
||||||
|
find.widgetWithText(Container, 'Frozen yogurt')
|
||||||
|
).size.height, 30.0);
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: Material(child: buildCustomTable(dataRowHeight: 56.0)),
|
||||||
|
));
|
||||||
|
expect(tester.renderObject<RenderBox>(
|
||||||
|
find.widgetWithText(Container, 'Frozen yogurt')
|
||||||
|
).size.height, 56.0);
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('DataTable custom horizontal padding - checkbox', (WidgetTester tester) async {
|
testWidgets('DataTable custom horizontal padding - checkbox', (WidgetTester tester) async {
|
||||||
const double _defaultHorizontalMargin = 24.0;
|
const double _defaultHorizontalMargin = 24.0;
|
||||||
const double _defaultColumnSpacing = 56.0;
|
const double _defaultColumnSpacing = 56.0;
|
||||||
|
@ -296,6 +296,86 @@ void main() {
|
|||||||
expect(find.text('Rows per page:'), findsOneWidget);
|
expect(find.text('Rows per page:'), findsOneWidget);
|
||||||
expect(tester.getTopLeft(find.text('Rows per page:')).dx, 18.0); // 14 padding in the footer row, 4 padding from the card
|
expect(tester.getTopLeft(find.text('Rows per page:')).dx, 18.0); // 14 padding in the footer row, 4 padding from the card
|
||||||
});
|
});
|
||||||
|
testWidgets('PaginatedDataTable custom row height', (WidgetTester tester) async {
|
||||||
|
final TestDataSource source = TestDataSource();
|
||||||
|
|
||||||
|
Widget buildCustomHeightPaginatedTable({
|
||||||
|
double dataRowHeight = 48.0,
|
||||||
|
double headingRowHeight = 56.0,
|
||||||
|
}) {
|
||||||
|
return PaginatedDataTable(
|
||||||
|
header: const Text('Test table'),
|
||||||
|
source: source,
|
||||||
|
rowsPerPage: 2,
|
||||||
|
availableRowsPerPage: const <int>[
|
||||||
|
2, 4, 8, 16,
|
||||||
|
],
|
||||||
|
onRowsPerPageChanged: (int rowsPerPage) {},
|
||||||
|
onPageChanged: (int rowIndex) {},
|
||||||
|
columns: const <DataColumn>[
|
||||||
|
DataColumn(label: Text('Name')),
|
||||||
|
DataColumn(label: Text('Calories'), numeric: true),
|
||||||
|
DataColumn(label: Text('Generation')),
|
||||||
|
],
|
||||||
|
dataRowHeight: dataRowHeight,
|
||||||
|
headingRowHeight: headingRowHeight,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEFAULT VALUES
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: PaginatedDataTable(
|
||||||
|
header: const Text('Test table'),
|
||||||
|
source: source,
|
||||||
|
rowsPerPage: 2,
|
||||||
|
availableRowsPerPage: const <int>[
|
||||||
|
2, 4, 8, 16,
|
||||||
|
],
|
||||||
|
onRowsPerPageChanged: (int rowsPerPage) {},
|
||||||
|
onPageChanged: (int rowIndex) {},
|
||||||
|
columns: const <DataColumn>[
|
||||||
|
DataColumn(label: Text('Name')),
|
||||||
|
DataColumn(label: Text('Calories'), numeric: true),
|
||||||
|
DataColumn(label: Text('Generation')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
));
|
||||||
|
expect(tester.renderObject<RenderBox>(
|
||||||
|
find.widgetWithText(Container, 'Name').first
|
||||||
|
).size.height, 56.0); // This is the header row height
|
||||||
|
expect(tester.renderObject<RenderBox>(
|
||||||
|
find.widgetWithText(Container, 'Frozen yogurt (0)').first
|
||||||
|
).size.height, 48.0); // This is the data row height
|
||||||
|
|
||||||
|
// CUSTOM VALUES
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: Material(child: buildCustomHeightPaginatedTable(headingRowHeight: 48.0)),
|
||||||
|
));
|
||||||
|
expect(tester.renderObject<RenderBox>(
|
||||||
|
find.widgetWithText(Container, 'Name').first
|
||||||
|
).size.height, 48.0);
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: Material(child: buildCustomHeightPaginatedTable(headingRowHeight: 64.0)),
|
||||||
|
));
|
||||||
|
expect(tester.renderObject<RenderBox>(
|
||||||
|
find.widgetWithText(Container, 'Name').first
|
||||||
|
).size.height, 64.0);
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: Material(child: buildCustomHeightPaginatedTable(dataRowHeight: 30.0)),
|
||||||
|
));
|
||||||
|
expect(tester.renderObject<RenderBox>(
|
||||||
|
find.widgetWithText(Container, 'Frozen yogurt (0)').first
|
||||||
|
).size.height, 30.0);
|
||||||
|
|
||||||
|
await tester.pumpWidget(MaterialApp(
|
||||||
|
home: Material(child: buildCustomHeightPaginatedTable(dataRowHeight: 56.0)),
|
||||||
|
));
|
||||||
|
expect(tester.renderObject<RenderBox>(
|
||||||
|
find.widgetWithText(Container, 'Frozen yogurt (0)').first
|
||||||
|
).size.height, 56.0);
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('PaginatedDataTable custom horizontal padding - checkbox', (WidgetTester tester) async {
|
testWidgets('PaginatedDataTable custom horizontal padding - checkbox', (WidgetTester tester) async {
|
||||||
const double _defaultHorizontalMargin = 24.0;
|
const double _defaultHorizontalMargin = 24.0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user