mirror of
https://github.com/flutter/flutter
synced 2024-10-13 11:42:54 +00:00
Added checkboxHorizontalMargin to DataTable and PaginatedDataTable (#71217)
This commit is contained in:
parent
19990c2d42
commit
bb43d2c632
|
@ -469,6 +469,7 @@ class DataTable extends StatelessWidget {
|
|||
this.showBottomBorder = false,
|
||||
this.dividerThickness,
|
||||
required this.rows,
|
||||
this.checkboxHorizontalMargin,
|
||||
}) : assert(columns != null),
|
||||
assert(columns.isNotEmpty),
|
||||
assert(sortColumnIndex == null || (sortColumnIndex >= 0 && sortColumnIndex < columns.length)),
|
||||
|
@ -636,6 +637,10 @@ class DataTable extends StatelessWidget {
|
|||
///
|
||||
/// If null, [DataTableThemeData.horizontalMargin] is used. This value
|
||||
/// defaults to 24.0 to adhere to the Material Design specifications.
|
||||
///
|
||||
/// If [checkboxHorizontalMargin] is null, then [horizontalMargin] is also the
|
||||
/// margin between the edge of the table and the checkbox, as well as the
|
||||
/// margin between the checkbox and the content in the first data column.
|
||||
final double? horizontalMargin;
|
||||
|
||||
/// {@template flutter.material.dataTable.columnSpacing}
|
||||
|
@ -679,6 +684,16 @@ class DataTable extends StatelessWidget {
|
|||
/// around the table defined by [decoration].
|
||||
final bool showBottomBorder;
|
||||
|
||||
/// {@template flutter.material.dataTable.checkboxHorizontalMargin}
|
||||
/// Horizontal margin around the checkbox, if it is displayed.
|
||||
/// {@endtemplate}
|
||||
///
|
||||
/// If null, [DataTableThemeData.checkboxHorizontalMargin] is used. If that is
|
||||
/// also null, then [horizontalMargin] is used as the margin between the edge
|
||||
/// of the table and the checkbox, as well as the margin between the checkbox
|
||||
/// and the content in the first data column. This value defaults to 24.0.
|
||||
final double? checkboxHorizontalMargin;
|
||||
|
||||
// Set by the constructor to the index of the only Column that is
|
||||
// non-numeric, if there is exactly one, otherwise null.
|
||||
final int? _onlyTextColumn;
|
||||
|
@ -746,12 +761,18 @@ class DataTable extends StatelessWidget {
|
|||
final double effectiveHorizontalMargin = horizontalMargin
|
||||
?? themeData.dataTableTheme.horizontalMargin
|
||||
?? _horizontalMargin;
|
||||
final double effectiveCheckboxHorizontalMarginStart = checkboxHorizontalMargin
|
||||
?? themeData.dataTableTheme.checkboxHorizontalMargin
|
||||
?? effectiveHorizontalMargin;
|
||||
final double effectiveCheckboxHorizontalMarginEnd = checkboxHorizontalMargin
|
||||
?? themeData.dataTableTheme.checkboxHorizontalMargin
|
||||
?? effectiveHorizontalMargin / 2.0;
|
||||
Widget contents = Semantics(
|
||||
container: true,
|
||||
child: Padding(
|
||||
padding: EdgeInsetsDirectional.only(
|
||||
start: effectiveHorizontalMargin,
|
||||
end: effectiveHorizontalMargin / 2.0,
|
||||
start: effectiveCheckboxHorizontalMarginStart,
|
||||
end: effectiveCheckboxHorizontalMarginEnd,
|
||||
),
|
||||
child: Center(
|
||||
child: Checkbox(
|
||||
|
@ -933,6 +954,12 @@ class DataTable extends StatelessWidget {
|
|||
final double effectiveHorizontalMargin = horizontalMargin
|
||||
?? theme.dataTableTheme.horizontalMargin
|
||||
?? _horizontalMargin;
|
||||
final double effectiveCheckboxHorizontalMarginStart = checkboxHorizontalMargin
|
||||
?? theme.dataTableTheme.checkboxHorizontalMargin
|
||||
?? effectiveHorizontalMargin;
|
||||
final double effectiveCheckboxHorizontalMarginEnd = checkboxHorizontalMargin
|
||||
?? theme.dataTableTheme.checkboxHorizontalMargin
|
||||
?? effectiveHorizontalMargin / 2.0;
|
||||
final double effectiveColumnSpacing = columnSpacing
|
||||
?? theme.dataTableTheme.columnSpacing
|
||||
?? _columnSpacing;
|
||||
|
@ -976,7 +1003,7 @@ class DataTable extends StatelessWidget {
|
|||
|
||||
int displayColumnIndex = 0;
|
||||
if (displayCheckboxColumn) {
|
||||
tableColumns[0] = FixedColumnWidth(effectiveHorizontalMargin + Checkbox.width + effectiveHorizontalMargin / 2.0);
|
||||
tableColumns[0] = FixedColumnWidth(effectiveCheckboxHorizontalMarginStart + Checkbox.width + effectiveCheckboxHorizontalMarginEnd);
|
||||
tableRows[0].children![0] = _buildCheckbox(
|
||||
context: context,
|
||||
checked: someChecked ? null : allChecked,
|
||||
|
@ -1004,7 +1031,9 @@ class DataTable extends StatelessWidget {
|
|||
final DataColumn column = columns[dataColumnIndex];
|
||||
|
||||
final double paddingStart;
|
||||
if (dataColumnIndex == 0 && displayCheckboxColumn) {
|
||||
if (dataColumnIndex == 0 && displayCheckboxColumn && checkboxHorizontalMargin != null) {
|
||||
paddingStart = effectiveHorizontalMargin;
|
||||
} else if (dataColumnIndex == 0 && displayCheckboxColumn) {
|
||||
paddingStart = effectiveHorizontalMargin / 2.0;
|
||||
} else if (dataColumnIndex == 0 && !displayCheckboxColumn) {
|
||||
paddingStart = effectiveHorizontalMargin;
|
||||
|
|
|
@ -45,6 +45,7 @@ class DataTableThemeData with Diagnosticable {
|
|||
this.horizontalMargin,
|
||||
this.columnSpacing,
|
||||
this.dividerThickness,
|
||||
this.checkboxHorizontalMargin,
|
||||
});
|
||||
|
||||
/// {@macro flutter.material.dataTable.decoration}
|
||||
|
@ -79,6 +80,9 @@ class DataTableThemeData with Diagnosticable {
|
|||
/// {@macro flutter.material.dataTable.dividerThickness}
|
||||
final double? dividerThickness;
|
||||
|
||||
/// {@macro flutter.material.dataTable.checkboxHorizontalMargin}
|
||||
final double? checkboxHorizontalMargin;
|
||||
|
||||
/// Creates a copy of this object but with the given fields replaced with the
|
||||
/// new values.
|
||||
DataTableThemeData copyWith({
|
||||
|
@ -92,6 +96,7 @@ class DataTableThemeData with Diagnosticable {
|
|||
double? horizontalMargin,
|
||||
double? columnSpacing,
|
||||
double? dividerThickness,
|
||||
double? checkboxHorizontalMargin,
|
||||
}) {
|
||||
return DataTableThemeData(
|
||||
decoration: decoration ?? this.decoration,
|
||||
|
@ -104,6 +109,7 @@ class DataTableThemeData with Diagnosticable {
|
|||
horizontalMargin: horizontalMargin ?? this.horizontalMargin,
|
||||
columnSpacing: columnSpacing ?? this.columnSpacing,
|
||||
dividerThickness: dividerThickness ?? this.dividerThickness,
|
||||
checkboxHorizontalMargin: checkboxHorizontalMargin ?? this.checkboxHorizontalMargin,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -124,7 +130,8 @@ class DataTableThemeData with Diagnosticable {
|
|||
headingTextStyle: TextStyle.lerp(a.headingTextStyle, b.headingTextStyle, t),
|
||||
horizontalMargin: lerpDouble(a.horizontalMargin, b.horizontalMargin, t),
|
||||
columnSpacing: lerpDouble(a.columnSpacing, b.columnSpacing, t),
|
||||
dividerThickness: lerpDouble(a.dividerThickness, b.dividerThickness, t)
|
||||
dividerThickness: lerpDouble(a.dividerThickness, b.dividerThickness, t),
|
||||
checkboxHorizontalMargin: lerpDouble(a.checkboxHorizontalMargin, b.checkboxHorizontalMargin, t)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -141,6 +148,7 @@ class DataTableThemeData with Diagnosticable {
|
|||
horizontalMargin,
|
||||
columnSpacing,
|
||||
dividerThickness,
|
||||
checkboxHorizontalMargin,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -160,7 +168,8 @@ class DataTableThemeData with Diagnosticable {
|
|||
&& other.headingTextStyle == headingTextStyle
|
||||
&& other.horizontalMargin == horizontalMargin
|
||||
&& other.columnSpacing == columnSpacing
|
||||
&& other.dividerThickness == dividerThickness;
|
||||
&& other.dividerThickness == dividerThickness
|
||||
&& other.checkboxHorizontalMargin == checkboxHorizontalMargin;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -176,6 +185,7 @@ class DataTableThemeData with Diagnosticable {
|
|||
properties.add(DoubleProperty('horizontalMargin', horizontalMargin, defaultValue: null));
|
||||
properties.add(DoubleProperty('columnSpacing', columnSpacing, defaultValue: null));
|
||||
properties.add(DoubleProperty('dividerThickness', dividerThickness, defaultValue: null));
|
||||
properties.add(DoubleProperty('checkboxHorizontalMargin', checkboxHorizontalMargin, defaultValue: null));
|
||||
}
|
||||
|
||||
static MaterialStateProperty<T>? _lerpProperties<T>(MaterialStateProperty<T>? a, MaterialStateProperty<T>? b, double t, T Function(T?, T?, double) lerpFunction ) {
|
||||
|
|
|
@ -86,6 +86,7 @@ class PaginatedDataTable extends StatefulWidget {
|
|||
this.onRowsPerPageChanged,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
required this.source,
|
||||
this.checkboxHorizontalMargin,
|
||||
}) : assert(actions == null || (actions != null && header != null)),
|
||||
assert(columns != null),
|
||||
assert(dragStartBehavior != null),
|
||||
|
@ -166,6 +167,10 @@ class PaginatedDataTable extends StatefulWidget {
|
|||
/// the content in the first data column.
|
||||
///
|
||||
/// This value defaults to 24.0 to adhere to the Material Design specifications.
|
||||
///
|
||||
/// If [checkboxHorizontalMargin] is null, then [horizontalMargin] is also the
|
||||
/// margin between the edge of the table and the checkbox, as well as the
|
||||
/// margin between the checkbox and the content in the first data column.
|
||||
final double horizontalMargin;
|
||||
|
||||
/// The horizontal margin between the contents of each data column.
|
||||
|
@ -224,6 +229,13 @@ class PaginatedDataTable extends StatefulWidget {
|
|||
/// {@macro flutter.widgets.scrollable.dragStartBehavior}
|
||||
final DragStartBehavior dragStartBehavior;
|
||||
|
||||
/// Horizontal margin around the checkbox, if it is displayed.
|
||||
///
|
||||
/// If null, then [horizontalMargin] is used as the margin between the edge
|
||||
/// of the table and the checkbox, as well as the margin between the checkbox
|
||||
/// and the content in the first data column. This value defaults to 24.0.
|
||||
final double? checkboxHorizontalMargin;
|
||||
|
||||
@override
|
||||
PaginatedDataTableState createState() => PaginatedDataTableState();
|
||||
}
|
||||
|
@ -513,6 +525,7 @@ class PaginatedDataTableState extends State<PaginatedDataTable> {
|
|||
dataRowHeight: widget.dataRowHeight,
|
||||
headingRowHeight: widget.headingRowHeight,
|
||||
horizontalMargin: widget.horizontalMargin,
|
||||
checkboxHorizontalMargin: widget.checkboxHorizontalMargin,
|
||||
columnSpacing: widget.columnSpacing,
|
||||
showCheckboxColumn: widget.showCheckboxColumn,
|
||||
showBottomBorder: true,
|
||||
|
|
|
@ -1540,4 +1540,93 @@ void main() {
|
|||
const Offset(width - borderVertical, height - borderHorizontal),
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('checkboxHorizontalMargin properly applied', (WidgetTester tester) async {
|
||||
const double _customCheckboxHorizontalMargin = 15.0;
|
||||
const double _customHorizontalMargin = 10.0;
|
||||
Finder cellContent;
|
||||
Finder checkbox;
|
||||
Finder padding;
|
||||
|
||||
Widget buildCustomTable({
|
||||
int? sortColumnIndex,
|
||||
bool sortAscending = true,
|
||||
double? horizontalMargin,
|
||||
double? checkboxHorizontalMargin,
|
||||
}) {
|
||||
return DataTable(
|
||||
sortColumnIndex: sortColumnIndex,
|
||||
sortAscending: sortAscending,
|
||||
onSelectAll: (bool? value) {},
|
||||
horizontalMargin: horizontalMargin,
|
||||
checkboxHorizontalMargin: checkboxHorizontalMargin,
|
||||
columns: <DataColumn>[
|
||||
const DataColumn(
|
||||
label: Text('Name'),
|
||||
tooltip: 'Name',
|
||||
),
|
||||
DataColumn(
|
||||
label: const Text('Calories'),
|
||||
tooltip: 'Calories',
|
||||
numeric: true,
|
||||
onSort: (int columnIndex, bool ascending) {},
|
||||
),
|
||||
DataColumn(
|
||||
label: const Text('Fat'),
|
||||
tooltip: 'Fat',
|
||||
numeric: true,
|
||||
onSort: (int columnIndex, bool ascending) {},
|
||||
),
|
||||
],
|
||||
rows: kDesserts.map<DataRow>((Dessert dessert) {
|
||||
return DataRow(
|
||||
key: ValueKey<String>(dessert.name),
|
||||
onSelectChanged: (bool? selected) {},
|
||||
cells: <DataCell>[
|
||||
DataCell(
|
||||
Text(dessert.name),
|
||||
),
|
||||
DataCell(
|
||||
Text('${dessert.calories}'),
|
||||
showEditIcon: true,
|
||||
onTap: () {},
|
||||
),
|
||||
DataCell(
|
||||
Text('${dessert.fat}'),
|
||||
showEditIcon: true,
|
||||
onTap: () {},
|
||||
),
|
||||
],
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
home: Material(child: buildCustomTable(
|
||||
checkboxHorizontalMargin: _customCheckboxHorizontalMargin,
|
||||
horizontalMargin: _customHorizontalMargin,
|
||||
)),
|
||||
));
|
||||
|
||||
// Custom checkbox padding.
|
||||
checkbox = find.byType(Checkbox).first;
|
||||
padding = find.ancestor(of: checkbox, matching: find.byType(Padding));
|
||||
expect(
|
||||
tester.getRect(checkbox).left - tester.getRect(padding).left,
|
||||
_customCheckboxHorizontalMargin,
|
||||
);
|
||||
expect(
|
||||
tester.getRect(padding).right - tester.getRect(checkbox).right,
|
||||
_customCheckboxHorizontalMargin,
|
||||
);
|
||||
|
||||
// First column padding.
|
||||
padding = find.widgetWithText(Padding, 'Frozen yogurt').first;
|
||||
cellContent = find.widgetWithText(Align, 'Frozen yogurt'); // DataTable wraps its DataCells in an Align widget.
|
||||
expect(
|
||||
tester.getRect(cellContent).left - tester.getRect(padding).left,
|
||||
_customHorizontalMargin,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ void main() {
|
|||
expect(themeData.horizontalMargin, null);
|
||||
expect(themeData.columnSpacing, null);
|
||||
expect(themeData.dividerThickness, null);
|
||||
expect(themeData.checkboxHorizontalMargin, null);
|
||||
|
||||
const DataTableTheme theme = DataTableTheme(data: DataTableThemeData(), child: SizedBox());
|
||||
expect(theme.data.decoration, null);
|
||||
|
@ -36,6 +37,7 @@ void main() {
|
|||
expect(theme.data.horizontalMargin, null);
|
||||
expect(theme.data.columnSpacing, null);
|
||||
expect(theme.data.dividerThickness, null);
|
||||
expect(theme.data.checkboxHorizontalMargin, null);
|
||||
});
|
||||
|
||||
testWidgets('Default DataTableThemeData debugFillProperties', (WidgetTester tester) async {
|
||||
|
@ -67,6 +69,7 @@ void main() {
|
|||
horizontalMargin: 3.0,
|
||||
columnSpacing: 4.0,
|
||||
dividerThickness: 5.0,
|
||||
checkboxHorizontalMargin: 6.0,
|
||||
).debugFillProperties(builder);
|
||||
|
||||
final List<String> description = builder.properties
|
||||
|
@ -84,6 +87,7 @@ void main() {
|
|||
expect(description[7], 'horizontalMargin: 3.0');
|
||||
expect(description[8], 'columnSpacing: 4.0');
|
||||
expect(description[9], 'dividerThickness: 5.0');
|
||||
expect(description[10], 'checkboxHorizontalMargin: 6.0');
|
||||
});
|
||||
|
||||
testWidgets('DataTable is themeable', (WidgetTester tester) async {
|
||||
|
|
|
@ -855,4 +855,72 @@ void main() {
|
|||
// Reset the surface size.
|
||||
await binding.setSurfaceSize(originalSize);
|
||||
});
|
||||
|
||||
testWidgets('PaginatedDataTable custom checkboxHorizontalMargin properly applied', (WidgetTester tester) async {
|
||||
const double _customCheckboxHorizontalMargin = 15.0;
|
||||
const double _customHorizontalMargin = 10.0;
|
||||
|
||||
const double _width = 400;
|
||||
const double _height = 400;
|
||||
|
||||
final Size originalSize = binding.renderView.size;
|
||||
|
||||
// Ensure the containing Card is small enough that we don't expand too
|
||||
// much, resulting in our custom margin being ignored.
|
||||
await binding.setSurfaceSize(const Size(_width, _height));
|
||||
|
||||
final TestDataSource source = TestDataSource(
|
||||
onSelectChanged: (bool? value) {},
|
||||
);
|
||||
Finder cellContent;
|
||||
Finder checkbox;
|
||||
Finder padding;
|
||||
|
||||
// CUSTOM VALUES
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
home: Material(
|
||||
child: PaginatedDataTable(
|
||||
header: const Text('Test table'),
|
||||
source: source,
|
||||
rowsPerPage: 2,
|
||||
availableRowsPerPage: const <int>[
|
||||
2, 4,
|
||||
],
|
||||
onRowsPerPageChanged: (int? rowsPerPage) {},
|
||||
onPageChanged: (int rowIndex) {},
|
||||
onSelectAll: (bool? value) {},
|
||||
columns: const <DataColumn>[
|
||||
DataColumn(label: Text('Name')),
|
||||
DataColumn(label: Text('Calories'), numeric: true),
|
||||
DataColumn(label: Text('Generation')),
|
||||
],
|
||||
horizontalMargin: _customHorizontalMargin,
|
||||
checkboxHorizontalMargin: _customCheckboxHorizontalMargin,
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
// Custom checkbox padding.
|
||||
checkbox = find.byType(Checkbox).first;
|
||||
padding = find.ancestor(of: checkbox, matching: find.byType(Padding)).first;
|
||||
expect(
|
||||
tester.getRect(checkbox).left - tester.getRect(padding).left,
|
||||
_customCheckboxHorizontalMargin,
|
||||
);
|
||||
expect(
|
||||
tester.getRect(padding).right - tester.getRect(checkbox).right,
|
||||
_customCheckboxHorizontalMargin,
|
||||
);
|
||||
|
||||
// Custom first column padding.
|
||||
padding = find.widgetWithText(Padding, 'Frozen yogurt (0)').first;
|
||||
cellContent = find.widgetWithText(Align, 'Frozen yogurt (0)'); // DataTable wraps its DataCells in an Align widget.
|
||||
expect(
|
||||
tester.getRect(cellContent).left - tester.getRect(padding).left,
|
||||
_customHorizontalMargin,
|
||||
);
|
||||
|
||||
// Reset the surface size.
|
||||
await binding.setSurfaceSize(originalSize);
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue