Skip to content

Feature request: specify a flexible width column for DataTable #51799

Closed

Description

@shaynekellyii

Use case

Currently, the DataTable column widths aren't flexible unless you only have one column that contains only text:

if (dataColumnIndex == _onlyTextColumn) {
    tableColumns[displayColumnIndex] = const IntrinsicColumnWidth(flex: 1.0);
} else {
    tableColumns[displayColumnIndex] = const IntrinsicColumnWidth();
}

It would be nice to be able to specify a column of your choice to have flexible width.

Proposal

Add a field like flexibleColumnIndex to DataTable that can be used to set the IntrinsicColumnWidth flex to 1.0 if the field is non-null.

I can put in a PR for this if this makes sense.

Activity

  1. added
    p: material_uimaterial_ui package in flutter/packages
    frameworkflutter/packages/flutter repository. See also f: labels.
    c: proposalA detailed proposal for a change to Flutter
    c: new featureNothing broken; request for a new capability
    on Mar 3, 2020
  2. lamnhan066 commented on Oct 5, 2024

    @lamnhan066
    Contributor

    Hi @Hixie, I would like to know your opinion on my idea for this issue. It works as expected on my side but I don't know how possible it is and if it has any side effects.

    Create a new type:

    typedef DataColumnWidthBuilder = TableColumnWidth? Function(int columnIndex);

    Add a new parameter to the DataTable:

    DataTable({
      // ...
      this.columnWidthBuilder,
      // ...
    });
    
    // ...
    final DataColumnWidthBuilder? columnWidthBuilder;
    // ...

    Modify this code from:

    if (dataColumnIndex == _onlyTextColumn) {
    tableColumns[displayColumnIndex] = const IntrinsicColumnWidth(flex: 1.0);
    } else {
    tableColumns[displayColumnIndex] = const IntrinsicColumnWidth();
    }

    To:

    final TableColumnWidth? tableColumnWidth = columnWidthBuilder?.call(displayColumnIndex);
    if (tableColumnWidth != null) {
      tableColumns[displayColumnIndex] = tableColumnWidth;
    } else {
      if (dataColumnIndex == _onlyTextColumn) {
        tableColumns[displayColumnIndex] = const IntrinsicColumnWidth(flex: 1.0);
      } else {
        tableColumns[displayColumnIndex] = const IntrinsicColumnWidth();
      }
    }

    Then we can use it like this to make it flexible for columns 0 and 1:

    Table(
      columnWidthBuilder: (columnIndex) {
        return switch (columnIndex) {
          0 => const IntrinsicColumnWidth(flex: 1),
          1 => const IntrinsicColumnWidth(flex: 2),
          _ => null,
        };
      },
      // ...
    )
  3. Hixie commented on Oct 7, 2024

    @Hixie
    Contributor

    At a glance I would probably make a custom ColumnWidth subclass rather than adding an API to DataTable et al. That minimizes the additional API surface internally, which minimizes the risk of introducing bugs. (Builders can be really tricky to get right because the semantics of when a builder should rebuild are not exactly obvious.)

  4. added
    P3Issues that are less important to the Flutter project
    on Oct 24, 2024
  5. lamnhan066 commented on Nov 1, 2024

    @lamnhan066
    Contributor

    Hi @Hixie

    I don't know if I understand your idea correctly, but I have a new idea. Instead of adding a new API to the DataTable, I added a columnWidth to DataColumn so we can easily create a DataColumn subclass.

    At first, I will add a columnWidth to DataColumn with a default null value to keep the old behavior.

    @immutable
    class DataColumn {
      /// Creates the configuration for a column of a [DataTable].
      const DataColumn({
        required this.label,
        this.columnWidth,
        this.tooltip,
        this.numeric = false,
        this.onSort,
        this.mouseCursor,
        this.headingRowAlignment,
      });
    
      // ...
    
      final TableColumnWidth? columnWidth;
    }

    Then, I modify the code to accept the new configuration from:

    if (dataColumnIndex == _onlyTextColumn) {
    tableColumns[displayColumnIndex] = const IntrinsicColumnWidth(flex: 1.0);
    } else {
    tableColumns[displayColumnIndex] = const IntrinsicColumnWidth();
    }

    To:

    if (column.columnWidth != null) {
      tableColumns[displayColumnIndex] = column.columnWidth!;
    } else {
      if (dataColumnIndex == _onlyTextColumn) {
        tableColumns[displayColumnIndex] = const IntrinsicColumnWidth(flex: 1.0);
      } else {
        tableColumns[displayColumnIndex] = const IntrinsicColumnWidth();
      }
    }

    So we can add a custom DataColumn like:

    class FlexDataColumn extends DataColumn {
      const FlexDataColumn({
        required super.label,
        this.flex = 1.0,
        super.tooltip,
        super.numeric = false,
        super.onSort,
        super.mouseCursor,
        super.headingRowAlignment,
      });
    
      final double flex;
    
      @override
      TableColumnWidth? get columnWidth => FlexColumnWidth(flex);
    }
    
    class IntrinsicDataColumn extends DataColumn {
      const IntrinsicDataColumn({
        required super.label,
        this.flex,
        super.tooltip,
        super.numeric = false,
        super.onSort,
        super.mouseCursor,
        super.headingRowAlignment,
      });
    
      final double? flex;
    
      @override
      TableColumnWidth? get columnWidth => IntrinsicColumnWidth(flex: flex);
    }
  6. Hixie commented on Nov 6, 2024

    @Hixie
    Contributor

    Is there a reason we can't implement this by literally creating a ColumnWidth subclass?

  7. Hixie commented on Nov 6, 2024

    @Hixie
    Contributor
  8. Hixie commented on Nov 6, 2024

    @Hixie
    Contributor

    (It's possible I don't understand what you're trying to do.)

  9. 1 remaining item

  10. Hixie commented on Nov 6, 2024

    @Hixie
    Contributor

    Oh, I see. Thanks for the explanation, that makes more sense to me now. :-)

    Should we just allow DataTable to be given the columnWidths directly, and have that override the default that it generates?

  11. lamnhan066 commented on Nov 7, 2024

    @lamnhan066
    Contributor

    I think we shouldn’t overwrite the columnWidths because we have a checkbox column that will be inserted into the Table if the showCheckboxColumn is true. So it becomes harder to control how the column width is implemented to avoid conflict between the new and the old DataTable (something like the index with a checkbox column is different from the index without it).

    Besides that, we already had the DataColumn to configure the columns, so we can configure the columnWidth easier if it’s here.

  12. Hixie commented on Nov 18, 2024

    @Hixie
    Contributor

    I see, I better understand where you're coming from now.

    Have you looked at adding a field on DataColumn that takes a TableColumnWidth, and then making the DataTable code use that if provided, and if not, falling back to what it currently does?

  13. lamnhan066 commented on Nov 18, 2024

    @lamnhan066
    Contributor

    @Hixie yes, that’s the flows I added.

  14. Hixie commented on Nov 19, 2024

    @Hixie
    Contributor

    In #51799 (comment) it looks like you're also adding new subclasses though? That's the part I don't understand.

  15. lamnhan066 commented on Nov 19, 2024

    @lamnhan066
    Contributor

    @Hixie

    The FlexDataColumn and IntrinsicDataColumn are optional subclasses. Those subclasses are extended from the DataColumn, which has the defaults columnWidth = FlexColumnWidth() and columnWidth = IntrinsicColumnWidth().

    So instead of using:

    DataTable(
      columns: [
        DataColumn(
          columnWidth: FlexDataColumn(3.0),
        ),
      ],
    )

    We can use:

    DataTable(
      columns: [
        FlexDataColumn(flex: 3.0),
      ],
    )
  16. Hixie commented on Nov 19, 2024

    @Hixie
    Contributor

    That seems like a very minor advantage given the additional complexity it introduces (anyone searching for "DataColumn" will now also find these other classes and have to figure out how they work together before they can understand the API).

  17. lamnhan066 commented on Nov 20, 2024

    @lamnhan066
    Contributor

    Should I open a PR for it without implementing those subclasses?

  18. Hixie commented on Nov 20, 2024

    @Hixie
    Contributor

    Worth a try!

  19. github-actions commented on Dec 6, 2024

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  20. locked as resolved and limited conversation to collaborators on Dec 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P3Issues that are less important to the Flutter projectc: new featureNothing broken; request for a new capabilityc: proposalA detailed proposal for a change to Flutterframeworkflutter/packages/flutter repository. See also f: labels.p: material_uimaterial_ui package in flutter/packagesr: solvedIssue is closed as solvedteam-designOwned by Design Languages teamtriaged-designTriaged by Design Languages team

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions