Unverified Commit ef5a6da3 authored by xubaolin's avatar xubaolin Committed by GitHub

Fix a `DataTable` crash and improve some docs (#100959)

parent fd360c4a
......@@ -33,21 +33,27 @@ class MyStatelessWidget extends StatelessWidget {
return DataTable(
columns: const <DataColumn>[
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),
),
),
),
],
......
......@@ -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;
......
......@@ -988,6 +988,7 @@ class RenderTable extends RenderBox {
// cache the table geometry for painting purposes
final List<double> _rowTops = <double>[];
Iterable<double>? _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<double> widths = _computeColumnWidths(constraints);
final List<double> positions = List<double>.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 <double>[], columns: const <double>[]);
}
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<double> rows = _rowTops.getRange(1, _rowTops.length - 1);
final Iterable<double> columns = _columnLefts!.skip(1);
border!.paint(context.canvas, borderRect, rows: rows, columns: columns);
......
......@@ -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<DataColumn> columns = <DataColumn>[
DataColumn(label: Text('column1')),
DataColumn(label: Text('column2')),
];
const List<DataCell> cells = <DataCell>[
DataCell(Text('cell1')),
DataCell(Text('cell2')),
];
const List<DataRow> rows = <DataRow>[
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.
});
}
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