Unverified Commit ee08c227 authored by Per Classon's avatar Per Classon Committed by GitHub

Add decoration parameter to DataTable and DataTableTheme (#66640)

* Add decoration parameter to DataTable and DataTableTheme
parent 0d8696f6
......@@ -10,6 +10,7 @@ import 'package:flutter/widgets.dart';
import 'checkbox.dart';
import 'constants.dart';
import 'data_table_theme.dart';
import 'debug.dart';
import 'divider.dart';
import 'dropdown.dart';
......@@ -411,6 +412,7 @@ class DataTable extends StatelessWidget {
this.sortColumnIndex,
this.sortAscending = true,
this.onSelectAll,
this.decoration,
this.dataRowColor,
this.dataRowHeight,
this.dataTextStyle,
......@@ -473,6 +475,14 @@ class DataTable extends StatelessWidget {
/// row is selectable.
final ValueSetter<bool?>? onSelectAll;
/// {@template flutter.material.dataTable.decoration}
/// The background and border decoration for the table.
/// {@endtemplate}
///
/// If null, [DataTableThemeData.decoration] is used. By default there is no
/// decoration.
final Decoration? decoration;
/// {@template flutter.material.dataTable.dataRowColor}
/// The background color for the data rows.
///
......@@ -484,9 +494,10 @@ class DataTable extends StatelessWidget {
/// color.
/// {@endtemplate}
///
/// By default, the background color is transparent unless selected. Selected
/// rows have a grey translucent color. To set a different color for
/// individual rows, see [DataRow.color].
/// If null, [DataTableThemeData.dataRowColor] is used. By default, the
/// background color is transparent unless selected. Selected rows have a grey
/// translucent color. To set a different color for individual rows, see
/// [DataRow.color].
///
/// {@template flutter.material.dataTable.dataRowColorCode}
/// ```dart
......@@ -511,15 +522,17 @@ class DataTable extends StatelessWidget {
/// The height of each row (excluding the row that contains column headings).
/// {@endtemplate}
///
/// This value defaults to [kMinInteractiveDimension] to adhere to the Material
/// Design specifications.
/// If null, [DataTableThemeData.dataRowHeight] is used. This value defaults
/// to [kMinInteractiveDimension] to adhere to the Material Design
/// specifications.
final double? dataRowHeight;
/// {@template flutter.material.dataTable.dataTextStyle}
/// The text style for data rows.
/// {@endtemplate}
///
/// By default, the text style is [TextTheme.bodyText2].
/// If null, [DataTableThemeData.dataTextStyle] is used. By default, the text
/// style is [TextTheme.bodyText2].
final TextStyle? dataTextStyle;
/// {@template flutter.material.dataTable.headingRowColor}
......@@ -530,7 +543,11 @@ class DataTable extends StatelessWidget {
/// sorted. The color is painted as an overlay to the row. To make sure that
/// the row's [InkWell] is visible (when pressed, hovered and focused), it is
/// recommended to use a translucent color.
/// {@endtemplate}
///
/// If null, [DataTableThemeData.headingRowColor] is used.
///
/// {@template flutter.material.dataTable.headingRowColorCode}
/// ```dart
/// DataTable(
/// headingRowColor: MaterialStateProperty.resolveWith<Color>((Set<MaterialState> states) {
......@@ -553,14 +570,16 @@ class DataTable extends StatelessWidget {
/// The height of the heading row.
/// {@endtemplate}
///
/// This value defaults to 56.0 to adhere to the Material Design specifications.
/// If null, [DataTableThemeData.headingRowHeight] is used. This value
/// defaults to 56.0 to adhere to the Material Design specifications.
final double? headingRowHeight;
/// {@template flutter.material.dataTable.headingTextStyle}
/// The text style for the heading row.
/// {@endtemplate}
///
/// By default, the text style is [TextTheme.subtitle2].
/// If null, [DataTableThemeData.headingTextStyle] is used. By default, the
/// text style is [TextTheme.subtitle2].
final TextStyle? headingTextStyle;
/// {@template flutter.material.dataTable.horizontalMargin}
......@@ -571,14 +590,16 @@ class DataTable extends StatelessWidget {
/// the content in the first data column.
/// {@endtemplate}
///
/// This value defaults to 24.0 to adhere to the Material Design specifications.
/// If null, [DataTableThemeData.horizontalMargin] is used. This value
/// defaults to 24.0 to adhere to the Material Design specifications.
final double? horizontalMargin;
/// {@template flutter.material.dataTable.columnSpacing}
/// The horizontal margin between the contents of each data column.
/// {@endtemplate}
///
/// This value defaults to 56.0 to adhere to the Material Design specifications.
/// If null, [DataTableThemeData.columnSpacing] is used. This value defaults
/// to 56.0 to adhere to the Material Design specifications.
final double? columnSpacing;
/// {@template flutter.material.dataTable.showCheckboxColumn}
......@@ -603,13 +624,15 @@ class DataTable extends StatelessWidget {
///
/// Must be greater than or equal to zero.
/// {@endtemplate}
/// This value defaults to 1.0.
///
/// If null, [DataTableThemeData.dividerThickness] is used. This value
/// defaults to 1.0.
final double? dividerThickness;
/// Whether a border at the bottom of the table is displayed.
///
/// By default, a border is not shown at the bottom to allow for a border
/// around the table.
/// around the table defined by [decoration].
final bool showBottomBorder;
// Set by the constructor to the index of the only Column that is
......@@ -975,9 +998,15 @@ class DataTable extends StatelessWidget {
displayColumnIndex += 1;
}
return Table(
columnWidths: tableColumns.asMap(),
children: tableRows,
return Container(
decoration: decoration ?? theme.dataTableTheme.decoration,
child: Material(
type: MaterialType.transparency,
child: Table(
columnWidths: tableColumns.asMap(),
children: tableRows,
),
),
);
}
}
......
......@@ -35,6 +35,7 @@ import 'theme.dart';
class DataTableThemeData with Diagnosticable {
/// Creates a theme that can be used for [ThemeData.dataTableTheme].
const DataTableThemeData({
this.decoration,
this.dataRowColor,
this.dataRowHeight,
this.dataTextStyle,
......@@ -46,6 +47,9 @@ class DataTableThemeData with Diagnosticable {
this.dividerThickness,
});
/// {@macro flutter.material.dataTable.decoration}
final Decoration? decoration;
/// {@macro flutter.material.dataTable.dataRowColor}
/// {@macro flutter.material.dataTable.dataRowColorCode}
final MaterialStateProperty<Color?>? dataRowColor;
......@@ -57,6 +61,7 @@ class DataTableThemeData with Diagnosticable {
final TextStyle? dataTextStyle;
/// {@macro flutter.material.dataTable.headingRowColor}
/// {@macro flutter.material.dataTable.headingRowColorCode}
final MaterialStateProperty<Color?>? headingRowColor;
/// {@macro flutter.material.dataTable.headingRowHeight}
......@@ -77,6 +82,7 @@ class DataTableThemeData with Diagnosticable {
/// Creates a copy of this object but with the given fields replaced with the
/// new values.
DataTableThemeData copyWith({
Decoration? decoration,
MaterialStateProperty<Color?>? dataRowColor,
double? dataRowHeight,
TextStyle? dataTextStyle,
......@@ -88,6 +94,7 @@ class DataTableThemeData with Diagnosticable {
double? dividerThickness,
}) {
return DataTableThemeData(
decoration: decoration ?? this.decoration,
dataRowColor: dataRowColor ?? this.dataRowColor,
dataRowHeight: dataRowHeight ?? this.dataRowHeight,
dataTextStyle: dataTextStyle ?? this.dataTextStyle,
......@@ -108,6 +115,7 @@ class DataTableThemeData with Diagnosticable {
static DataTableThemeData lerp(DataTableThemeData a, DataTableThemeData b, double t) {
assert(t != null);
return DataTableThemeData(
decoration: Decoration.lerp(a.decoration, b.decoration, t),
dataRowColor: _lerpProperties<Color?>(a.dataRowColor, b.dataRowColor, t, Color.lerp),
dataRowHeight: lerpDouble(a.dataRowHeight, b.dataRowHeight, t),
dataTextStyle: TextStyle.lerp(a.dataTextStyle, b.dataTextStyle, t),
......@@ -123,6 +131,7 @@ class DataTableThemeData with Diagnosticable {
@override
int get hashCode {
return hashValues(
decoration,
dataRowColor,
dataRowHeight,
dataTextStyle,
......@@ -142,6 +151,7 @@ class DataTableThemeData with Diagnosticable {
if (other.runtimeType != runtimeType)
return false;
return other is DataTableThemeData
&& other.decoration == decoration
&& other.dataRowColor == dataRowColor
&& other.dataRowHeight == dataRowHeight
&& other.dataTextStyle == dataTextStyle
......@@ -156,6 +166,7 @@ class DataTableThemeData with Diagnosticable {
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DiagnosticsProperty<Decoration>('decoration', decoration, defaultValue: null));
properties.add(DiagnosticsProperty<MaterialStateProperty<Color?>>('dataRowColor', dataRowColor, defaultValue: null));
properties.add(DoubleProperty('dataRowHeight', dataRowHeight, defaultValue: null));
properties.add(DiagnosticsProperty<TextStyle>('dataTextStyle', dataTextStyle, defaultValue: null));
......
......@@ -471,41 +471,35 @@ void main() {
),
),
));
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
// The finder matches with the Container of the cell content, as well as the
// Container wrapping the whole table. The first one is used to test row
// heights.
Finder findFirstContainerFor(String text) => find.widgetWithText(Container, text).first;
expect(tester.getSize(findFirstContainerFor('Name')).height, 56.0);
expect(tester.getSize(findFirstContainerFor('Frozen yogurt')).height, 48.0);
// 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);
expect(tester.getSize(findFirstContainerFor('Name')).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);
expect(tester.getSize(findFirstContainerFor('Name')).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);
expect(tester.getSize(findFirstContainerFor('Frozen yogurt')).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);
expect(tester.getSize(findFirstContainerFor('Frozen yogurt')).height, 56.0);
});
testWidgets('DataTable custom horizontal padding - checkbox', (WidgetTester tester) async {
......@@ -1303,4 +1297,56 @@ void main() {
expect(tester.takeException(), isNull);
});
testWidgets('DataTable renders with border and background decoration', (WidgetTester tester) async {
const double width = 800;
const double height = 600;
const double borderHorizontal = 5.0;
const double borderVertical = 10.0;
const Color borderColor = Color(0xff2196f3);
const Color backgroundColor = Color(0xfff5f5f5);
await tester.pumpWidget(
MaterialApp(
home: DataTable(
decoration: const BoxDecoration(
color: backgroundColor,
border: Border.symmetric(
vertical: BorderSide(width: borderVertical, color: borderColor),
horizontal: BorderSide(width: borderHorizontal, color: borderColor),
),
),
columns: const <DataColumn>[
DataColumn(label: Text('Col1')),
],
rows: const <DataRow>[
DataRow(cells: <DataCell>[DataCell(Text('1'))]),
],
),
),
);
expect(
find.ancestor(of: find.byType(Table), matching: find.byType(Container)),
paints..rect(
rect: const Rect.fromLTRB(0.0, 0.0, width, height),
color: backgroundColor,
),
);
expect(
find.ancestor(of: find.byType(Table), matching: find.byType(Container)),
paints
..path(color: borderColor)
..path(color: borderColor)
..path(color: borderColor)
..path(color: borderColor),
);
expect(
tester.getTopLeft(find.byType(Table)),
const Offset(borderVertical, borderHorizontal),
);
expect(
tester.getBottomRight(find.byType(Table)),
const Offset(width - borderVertical, height - borderHorizontal),
);
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment