diff --git a/examples/api/lib/material/data_table/data_table.0.dart b/examples/api/lib/material/data_table/data_table.0.dart index eb2167aee2a..5d110c8fbf6 100644 --- a/examples/api/lib/material/data_table/data_table.0.dart +++ b/examples/api/lib/material/data_table/data_table.0.dart @@ -33,21 +33,27 @@ class MyStatelessWidget extends StatelessWidget { return DataTable( columns: const [ DataColumn( - label: Text( - 'Name', - style: TextStyle(fontStyle: FontStyle.italic), + label: Expanded( + child: Text( + 'Name', + style: TextStyle(fontStyle: FontStyle.italic), + ), ), ), DataColumn( - label: Text( - 'Age', - style: TextStyle(fontStyle: FontStyle.italic), + label: Expanded( + child: Text( + 'Age', + style: TextStyle(fontStyle: FontStyle.italic), + ), ), ), DataColumn( - label: Text( - 'Role', - style: TextStyle(fontStyle: FontStyle.italic), + label: Expanded( + child: Text( + 'Role', + style: TextStyle(fontStyle: FontStyle.italic), + ), ), ), ], diff --git a/packages/flutter/lib/src/material/data_table.dart b/packages/flutter/lib/src/material/data_table.dart index 9bfaf8d4902..8d936f5c78d 100644 --- a/packages/flutter/lib/src/material/data_table.dart +++ b/packages/flutter/lib/src/material/data_table.dart @@ -47,9 +47,14 @@ class DataColumn { /// [Icon] (typically using size 18), or a [Row] with an icon and /// some text. /// - /// By default, this widget will only occupy the minimal space. If you want - /// it to take the entire remaining space, e.g. when you want to use [Center], - /// you can wrap it with an [Expanded]. + /// The [label] is placed within a [Row] along with the + /// sort indicator (if applicable). By default, [label] only occupy minimal + /// space. It is recommended to place the label content in an [Expanded] or + /// [Flexible] as [label] to control how the content flexes. Otherwise, + /// an exception will occur when the available space is insufficient. + /// + /// By default, [DefaultTextStyle.softWrap] of this subtree will be set to false. + /// Use [DefaultTextStyle.merge] to override it if needed. /// /// The label should not include the sort indicator. final Widget label; diff --git a/packages/flutter/lib/src/rendering/table.dart b/packages/flutter/lib/src/rendering/table.dart index c0fdc35fcab..cd45040aae4 100644 --- a/packages/flutter/lib/src/rendering/table.dart +++ b/packages/flutter/lib/src/rendering/table.dart @@ -988,6 +988,7 @@ class RenderTable extends RenderBox { // cache the table geometry for painting purposes final List _rowTops = []; Iterable? _columnLefts; + late double _tableWidth; /// Returns the position and dimensions of the box that the given /// row covers, in this render object's coordinate space (so the @@ -1050,26 +1051,26 @@ class RenderTable extends RenderBox { if (rows * columns == 0) { // TODO(ianh): if columns is zero, this should be zero width // TODO(ianh): if columns is not zero, this should be based on the column width specifications + _tableWidth = 0.0; size = constraints.constrain(Size.zero); return; } final List widths = _computeColumnWidths(constraints); final List positions = List.filled(columns, 0.0); - final double tableWidth; switch (textDirection) { case TextDirection.rtl: positions[columns - 1] = 0.0; for (int x = columns - 2; x >= 0; x -= 1) positions[x] = positions[x+1] + widths[x+1]; _columnLefts = positions.reversed; - tableWidth = positions.first + widths.first; + _tableWidth = positions.first + widths.first; break; case TextDirection.ltr: positions[0] = 0.0; for (int x = 1; x < columns; x += 1) positions[x] = positions[x-1] + widths[x-1]; _columnLefts = positions; - tableWidth = positions.last + widths.last; + _tableWidth = positions.last + widths.last; break; } _rowTops.clear(); @@ -1150,7 +1151,7 @@ class RenderTable extends RenderBox { rowTop += rowHeight; } _rowTops.add(rowTop); - size = constraints.constrain(Size(tableWidth, rowTop)); + size = constraints.constrain(Size(_tableWidth, rowTop)); assert(_rowTops.length == rows + 1); } @@ -1181,7 +1182,7 @@ class RenderTable extends RenderBox { assert(_children.length == rows * columns); if (rows * columns == 0) { if (border != null) { - final Rect borderRect = Rect.fromLTWH(offset.dx, offset.dy, size.width, 0.0); + final Rect borderRect = Rect.fromLTWH(offset.dx, offset.dy, _tableWidth, 0.0); border!.paint(context.canvas, borderRect, rows: const [], columns: const []); } return; @@ -1216,7 +1217,7 @@ class RenderTable extends RenderBox { // The border rect might not fill the entire height of this render object // if the rows underflow. We always force the columns to fill the width of // the render object, which means the columns cannot underflow. - final Rect borderRect = Rect.fromLTWH(offset.dx, offset.dy, size.width, _rowTops.last); + final Rect borderRect = Rect.fromLTWH(offset.dx, offset.dy, _tableWidth, _rowTops.last); final Iterable rows = _rowTops.getRange(1, _rowTops.length - 1); final Iterable columns = _columnLefts!.skip(1); border!.paint(context.canvas, borderRect, rows: rows, columns: columns); diff --git a/packages/flutter/test/material/data_table_test.dart b/packages/flutter/test/material/data_table_test.dart index 64e9c1251be..182d0430652 100644 --- a/packages/flutter/test/material/data_table_test.dart +++ b/packages/flutter/test/material/data_table_test.dart @@ -1855,4 +1855,42 @@ void main() { expect(tableBorder?.bottom.width, null); expect(tableBorder?.top.color, null); }); + + // Regression test for https://github.com/flutter/flutter/issues/100952 + testWidgets('Do not crashes when paint borders in a narrow space', (WidgetTester tester) async { + const List columns = [ + DataColumn(label: Text('column1')), + DataColumn(label: Text('column2')), + ]; + + const List cells = [ + DataCell(Text('cell1')), + DataCell(Text('cell2')), + ]; + + const List rows = [ + DataRow(cells: cells), + DataRow(cells: cells), + ]; + + await tester.pumpWidget( + MaterialApp( + home: Material( + child: Center( + child: SizedBox( + width: 117.0, + child: DataTable( + border: TableBorder.all(width: 2, color: Colors.red), + columns: columns, + rows: rows, + ), + ), + ), + ), + ), + ); + + // Go without crashes. + + }); }