diff --git a/packages/flutter/lib/src/rendering/table.dart b/packages/flutter/lib/src/rendering/table.dart index 926dc60902..6bb3f8ec7f 100644 --- a/packages/flutter/lib/src/rendering/table.dart +++ b/packages/flutter/lib/src/rendering/table.dart @@ -918,10 +918,7 @@ class RenderTable extends RenderBox { // columns shrinking them proportionally until we have no // available columns, then do the same to the non-flexible ones. int availableColumns = columns; - // Handle double precision errors which causes this loop to become - // stuck in certain configurations. - const double minimumDeficit = precisionErrorTolerance; - while (deficit > minimumDeficit && totalFlex > minimumDeficit) { + while (deficit > precisionErrorTolerance && totalFlex > precisionErrorTolerance) { double newTotalFlex = 0.0; for (int x = 0; x < columns; x += 1) { if (flexes[x] != null) { @@ -943,31 +940,30 @@ class RenderTable extends RenderBox { } totalFlex = newTotalFlex; } - if (deficit > 0.0) { + while (deficit > precisionErrorTolerance && availableColumns > 0) { // Now we have to take out the remaining space from the // columns that aren't minimum sized. // To make this fair, we repeatedly remove equal amounts from // each column, clamped to the minimum width, until we run out // of columns that aren't at their minWidth. - do { - final double delta = deficit / availableColumns; - int newAvailableColumns = 0; - for (int x = 0; x < columns; x += 1) { - final double availableDelta = widths[x] - minWidths[x]; - if (availableDelta > 0.0) { - if (availableDelta <= delta) { - // shrank to minimum - deficit -= widths[x] - minWidths[x]; - widths[x] = minWidths[x]; - } else { - deficit -= delta; - widths[x] -= delta; - newAvailableColumns += 1; - } + final double delta = deficit / availableColumns; + assert(delta != 0); + int newAvailableColumns = 0; + for (int x = 0; x < columns; x += 1) { + final double availableDelta = widths[x] - minWidths[x]; + if (availableDelta > 0.0) { + if (availableDelta <= delta) { + // shrank to minimum + deficit -= widths[x] - minWidths[x]; + widths[x] = minWidths[x]; + } else { + deficit -= delta; + widths[x] -= delta; + newAvailableColumns += 1; } } - availableColumns = newAvailableColumns; - } while (deficit > 0.0 && availableColumns > 0); + } + availableColumns = newAvailableColumns; } } return widths; diff --git a/packages/flutter/test/rendering/table_test.dart b/packages/flutter/test/rendering/table_test.dart index 87571fbd27..bae9252411 100644 --- a/packages/flutter/test/rendering/table_test.dart +++ b/packages/flutter/test/rendering/table_test.dart @@ -217,4 +217,30 @@ void main() { pumpFrame(); expect(table, paints..path()..path()..path()..path()..path()..path()); }); + + test('Table flex sizing', () { + const BoxConstraints cellConstraints = + BoxConstraints.tightFor(width: 100, height: 100); + final RenderTable table = RenderTable( + textDirection: TextDirection.rtl, + children: >[ + List.generate( + 7, + (int _) => RenderConstrainedBox(additionalConstraints: cellConstraints), + ), + ], + columnWidths: const { + 0: FlexColumnWidth(1.0), + 1: FlexColumnWidth(0.123), + 2: FlexColumnWidth(0.123), + 3: FlexColumnWidth(0.123), + 4: FlexColumnWidth(0.123), + 5: FlexColumnWidth(0.123), + 6: FlexColumnWidth(0.123), + }, + ); + + layout(table, constraints: BoxConstraints.tight(const Size(800.0, 600.0))); + expect(table.hasSize, true); + }); } diff --git a/packages/flutter/test/widgets/table_test.dart b/packages/flutter/test/widgets/table_test.dart index 3614d1e22b..7d2797a135 100644 --- a/packages/flutter/test/widgets/table_test.dart +++ b/packages/flutter/test/widgets/table_test.dart @@ -376,6 +376,36 @@ void main() { // If the above bug is present this test will never terminate. }); + testWidgets('Calculating flex columns with small width deficit', (WidgetTester tester) async { + const SizedBox cell = SizedBox(width: 1, height: 1); + // If the error is present, pumpWidget() will fail due to an unsatisfied + // assertion during the layout phase. + await tester.pumpWidget( + ConstrainedBox( + constraints: BoxConstraints.tight(const Size(600, 800)), + child: Directionality( + textDirection: TextDirection.ltr, + child: Table( + columnWidths: const { + 0: FlexColumnWidth(1.0), + 1: FlexColumnWidth(0.123), + 2: FlexColumnWidth(0.123), + 3: FlexColumnWidth(0.123), + 4: FlexColumnWidth(0.123), + 5: FlexColumnWidth(0.123), + 6: FlexColumnWidth(0.123), + }, + children: [ + TableRow(children: List.filled(7, cell)), + TableRow(children: List.filled(7, cell)), + ], + ), + ), + ), + ); + expect(tester.takeException(), null); + }); + testWidgets('Table widget - repump test', (WidgetTester tester) async { await tester.pumpWidget( Directionality(