diff --git a/packages/flutter/lib/src/material/data_table.dart b/packages/flutter/lib/src/material/data_table.dart index 4d9c29f06c5..3f87bfcd402 100644 --- a/packages/flutter/lib/src/material/data_table.dart +++ b/packages/flutter/lib/src/material/data_table.dart @@ -330,6 +330,7 @@ class DataTable extends StatelessWidget { this.headingRowHeight = 56.0, this.horizontalMargin = 24.0, this.columnSpacing = 56.0, + this.showCheckboxColumn = true, @required this.rows, }) : assert(columns != null), assert(columns.isNotEmpty), @@ -339,6 +340,7 @@ class DataTable extends StatelessWidget { assert(headingRowHeight != null), assert(horizontalMargin != null), assert(columnSpacing != null), + assert(showCheckboxColumn != null), assert(rows != null), assert(!rows.any((DataRow row) => row.cells.length != columns.length)), _onlyTextColumn = _initOnlyTextColumn(columns), @@ -408,6 +410,17 @@ class DataTable extends StatelessWidget { /// This value defaults to 56.0 to adhere to the Material Design specifications. final double columnSpacing; + /// {@template flutter.material.dataTable.showCheckboxColumn} + /// Whether the widget should display checkboxes for selectable rows. + /// + /// If true, a [CheckBox] will be placed at the beginning of each row that is + /// selectable. However, if [DataRow.onSelectChanged] is not set for any row, + /// checkboxes will not be placed, even if this value is true. + /// + /// If false, all rows will not display a [CheckBox]. + /// {@endtemplate} + final bool showCheckboxColumn; + /// The data to show in each row (excluding the row that contains /// the column headings). /// @@ -608,10 +621,10 @@ class DataTable extends StatelessWidget { border: Border(bottom: Divider.createBorderSide(context, width: 1.0)), ); - final bool showCheckboxColumn = rows.any((DataRow row) => row.onSelectChanged != null); - final bool allChecked = showCheckboxColumn && !rows.any((DataRow row) => row.onSelectChanged != null && !row.selected); + final bool displayCheckboxColumn = showCheckboxColumn && rows.any((DataRow row) => row.onSelectChanged != null); + final bool allChecked = displayCheckboxColumn && !rows.any((DataRow row) => row.onSelectChanged != null && !row.selected); - final List tableColumns = List(columns.length + (showCheckboxColumn ? 1 : 0)); + final List tableColumns = List(columns.length + (displayCheckboxColumn ? 1 : 0)); final List tableRows = List.generate( rows.length + 1, // the +1 is for the header row (int index) { @@ -627,7 +640,7 @@ class DataTable extends StatelessWidget { int rowIndex; int displayColumnIndex = 0; - if (showCheckboxColumn) { + if (displayCheckboxColumn) { tableColumns[0] = FixedColumnWidth(horizontalMargin + Checkbox.width + horizontalMargin / 2.0); tableRows[0].children[0] = _buildCheckbox( color: theme.accentColor, @@ -651,9 +664,9 @@ class DataTable extends StatelessWidget { final DataColumn column = columns[dataColumnIndex]; double paddingStart; - if (dataColumnIndex == 0 && showCheckboxColumn) { + if (dataColumnIndex == 0 && displayCheckboxColumn) { paddingStart = horizontalMargin / 2.0; - } else if (dataColumnIndex == 0 && !showCheckboxColumn) { + } else if (dataColumnIndex == 0 && !displayCheckboxColumn) { paddingStart = horizontalMargin; } else { paddingStart = columnSpacing / 2.0; diff --git a/packages/flutter/lib/src/material/paginated_data_table.dart b/packages/flutter/lib/src/material/paginated_data_table.dart index 50147a48a04..4f634d86188 100644 --- a/packages/flutter/lib/src/material/paginated_data_table.dart +++ b/packages/flutter/lib/src/material/paginated_data_table.dart @@ -74,6 +74,7 @@ class PaginatedDataTable extends StatefulWidget { this.headingRowHeight = 56.0, this.horizontalMargin = 24.0, this.columnSpacing = 56.0, + this.showCheckboxColumn = true, this.initialFirstRowIndex = 0, this.onPageChanged, this.rowsPerPage = defaultRowsPerPage, @@ -91,6 +92,7 @@ class PaginatedDataTable extends StatefulWidget { assert(headingRowHeight != null), assert(horizontalMargin != null), assert(columnSpacing != null), + assert(showCheckboxColumn != null), assert(rowsPerPage != null), assert(rowsPerPage > 0), assert(() { @@ -164,6 +166,9 @@ class PaginatedDataTable extends StatefulWidget { /// This value defaults to 56.0 to adhere to the Material Design specifications. final double columnSpacing; + /// {@macro flutter.material.dataTable.showCheckboxColumn} + final bool showCheckboxColumn; + /// The index of the first row to display when the widget is first created. final int initialFirstRowIndex; @@ -465,6 +470,7 @@ class PaginatedDataTableState extends State { headingRowHeight: widget.headingRowHeight, horizontalMargin: widget.horizontalMargin, columnSpacing: widget.columnSpacing, + showCheckboxColumn: widget.showCheckboxColumn, rows: _getRows(_firstRowIndex, widget.rowsPerPage), ), ), diff --git a/packages/flutter/test/material/data_table_test.dart b/packages/flutter/test/material/data_table_test.dart index 4a9d5597722..4763962f3c5 100644 --- a/packages/flutter/test/material/data_table_test.dart +++ b/packages/flutter/test/material/data_table_test.dart @@ -99,6 +99,72 @@ void main() { log.clear(); }); + testWidgets('DataTable control test - no checkboxes', (WidgetTester tester) async { + final List log = []; + + Widget buildTable({ bool checkboxes = false }) { + return DataTable( + showCheckboxColumn: checkboxes, + onSelectAll: (bool value) { + log.add('select-all: $value'); + }, + columns: const [ + DataColumn( + label: Text('Name'), + tooltip: 'Name', + ), + DataColumn( + label: Text('Calories'), + tooltip: 'Calories', + numeric: true, + ), + ], + rows: kDesserts.map((Dessert dessert) { + return DataRow( + key: ValueKey(dessert.name), + onSelectChanged: (bool selected) { + log.add('row-selected: ${dessert.name}'); + }, + cells: [ + DataCell( + Text(dessert.name), + ), + DataCell( + Text('${dessert.calories}'), + showEditIcon: true, + onTap: () { + log.add('cell-tap: ${dessert.calories}'); + }, + ), + ], + ); + }).toList(), + ); + } + + await tester.pumpWidget(MaterialApp( + home: Material(child: buildTable()), + )); + + expect(find.byType(Checkbox), findsNothing); + await tester.tap(find.text('Cupcake')); + + expect(log, ['row-selected: Cupcake']); + log.clear(); + + await tester.pumpWidget(MaterialApp( + home: Material(child: buildTable(checkboxes: true)), + )); + + await tester.pumpAndSettle(const Duration(milliseconds: 200)); + final Finder checkboxes = find.byType(Checkbox); + expect(checkboxes, findsNWidgets(11)); + await tester.tap(checkboxes.first); + + expect(log, ['select-all: true']); + log.clear(); + }); + testWidgets('DataTable overflow test - header', (WidgetTester tester) async { await tester.pumpWidget( MaterialApp(