Skip to content

Table logic error causes flex columns to collapse to minimum widths in certain combinations of table width and number of columns #30437

@champeauxr

Description

@champeauxr

Certain combinations of width constraints for a table and the number of flex columns results in a logic error that collapses the flex columns to their minimum widths. If their minimum width is zero, then they are collapsed to zero width and are not rendered.

The following code reproduces the problem:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final blocks = <Widget>[
      Container(height: 60, color: Colors.red,),
      Container(height: 60, color: Colors.green,),
      Container(height: 60, color: Colors.blue,),
      Container(height: 60, color: Colors.yellow,),
      Container(height: 60, color: Colors.brown,),
      Container(height: 60, color: Colors.purple,),
    ];

    return Scaffold(
      body: Container(
        width: 100.0,
        child: Table(
          children: [TableRow(children: blocks)],
        ),
      ),
    );
  }
}

This code should produce a 100 unit wide rectangle consisting of 6 colored blocks, but it renders an empty screen. If you comment out one of the Containers in the blocks list, it will correctly render a 100 unit wide rectangle with 5 colored blocks.

I tracked down the problem and it is a logic error in RenderTable._computeColumnWidths(BoxConstraints constraints)

The logic error is in the following loop at the end of _computeColumnWidths()

      if (deficit > 0.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 -= availableDelta;
                widths[x] -= availableDelta;
                newAvailableColumns += 1;
              }
            }
          }
          availableColumns = newAvailableColumns;
        } while (deficit > 0.0 && availableColumns > 0);
      }

After the flex columns are grown to fill the width constraint and if the table size is now greater than the constraint, this loop is supposed to evenly remove a portion of the deficit from each flex column to bring the table width into the constraint. Instead it removes all of flex space in each column and in the example code reduces every column to zero width.

The error is in the last if/else statement:

              if (availableDelta <= delta) {
                // shrank to minimum
                deficit -= widths[x] - minWidths[x];
                widths[x] = minWidths[x];
              } else {
                deficit -= availableDelta;
                widths[x] -= availableDelta;
                newAvailableColumns += 1;
              }

The delta variable was calculated to be the even portion of the deficit that is to be subtracted from each column:

final double delta = deficit / availableColumns;

The if/else statement is supposed to remove the availableDelta from a column width if availableDelta is less than delta, otherwise it should be subtracting delta from the columnWidth.

Instead, if availableDelta is greater than delta, it's removing all of availableDelta from the column width, which collapses it to its minimum width.

This code

              } else {
                deficit -= availableDelta;
                widths[x] -= availableDelta;
                newAvailableColumns += 1;
              }

should instead be

              } else {
                deficit -= delta;
                widths[x] -= delta;
                newAvailableColumns += 1;
              }

Metadata

Metadata

Assignees

No one assigned

    Labels

    frameworkflutter/packages/flutter repository. See also f: labels.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions