rickypid / flutter_expandable_table

A Flutter widget for create an expandable table with header and first column fixed.
https://pub.dev/packages/flutter_expandable_table
BSD 3-Clause "New" or "Revised" License
38 stars 28 forks source link

Not working well with ValueListenableBuilder #29

Closed valiant-09 closed 6 months ago

valiant-09 commented 8 months ago

Each time I try to re-build the table as I have some functionality to filter the columns, if I print the data inside the build method, it prints the updated data, but the columns remain the same, until I move away from this screen and come back again. I pass my data as the Constructor Attribute.


`import 'package:flutter/material.dart';
import 'package:flutter_expandable_table/flutter_expandable_table.dart';

import '../../../constants.dart';
import '../../dashboard/components/default_cell_card.dart';

///Make a table that places the company names as columns,
///policy names as first row, and places an icon on each cell to indicate
///whether the company has that policy or not
class DynamicTable extends StatefulWidget {
  const DynamicTable({super.key, required this.data});

  ///the transformed Map to be used for rows and columns
  final Map<String, Map<String, double>> data;

  @override
  State<DynamicTable> createState() => _DynamicTableState();
}

class _DynamicTableState extends State<DynamicTable> {
  Color primaryColor = Colors.white; //corner
  Color accentColor = const Color(0xffffdc6e); //background
  TextStyle textStyle =
      const TextStyle(color: bgColor, fontWeight: FontWeight.bold);
  TextStyle textStyleSubItems = const TextStyle(color: Colors.grey);

  _buildCell(String content, {CellBuilder? builder}) {
    return ExpandableTableCell(
      child: builder != null
          ? null
          : DefaultCellCard(
              child: Center(
                child: Text(
                  content,
                  style: textStyle,
                ),
              ),
            ),
      builder: builder,
    );
  }

  ///Make a table cell that has formatting that allows the text to be aligned
  /// as centerLeft
  _buildCellPolicyName(String content, {CellBuilder? builder}) {
    return ExpandableTableCell(
      child: builder != null
          ? null
          : DefaultCellCard(
              child: Center(
                child: Align(
                  alignment: Alignment.centerLeft,
                  child: Text(
                    content,
                    style: const TextStyle(
                      color: bgColor,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ),
              ),
            ),
      builder: builder,
    );
  }

  ///Instead of placing the values 1 or 0, place a green check icon for 1,
  ///and place a red block icon for 0
  _buildCellIcons(double value, {CellBuilder? builder}) {
    return ExpandableTableCell(
      child: builder != null
          ? null
          : DefaultCellCard(
              child: Center(
                child: _setIcon(value),
              ),
            ),
      builder: builder,
    );
  }

  ///Given the policyName as key and the Map of it's value map, make a row
  ///By placing the policyName as first cell, and the rest of the values as
  ///icons for each company.
  ExpandableTableRow _getRow(String policyName, Map<String, double> companies) {
    List<ExpandableTableCell> cells = [];
    // //add policy name in first cell
    // cells.add(_buildCell(policyName));
    // Iterate through company values and add cells with 1 or 0 accordingly
    companies.forEach((companyName, value) {
      cells.add(_buildCellIcons(value));
    });

    return ExpandableTableRow(
        firstCell: _buildCellPolicyName(policyName), cells: cells, height: 50);
  }

  ///Make the ExpandableTable by setting up the headers and rows, and other
  ///relevant customizations
  ExpandableTable _buildTable() {
    //make all company names as columns
    List<ExpandableTableHeader> headers = [
      ...widget.data.values.first.keys.map((companyName) =>
          ExpandableTableHeader(
              cell: _buildCell(companyName),
              width: 200,
              disableDefaultOnTapExpansion: true)),
    ];
    //make the policy and each company value as rows
    List<ExpandableTableRow> rows = [];
    widget.data.forEach((policyName, companies) {
      rows.add(_getRow(policyName, companies));
    });

    return ExpandableTable(
      firstHeaderCell: _buildCell(''),
      headers: headers,
      headerHeight: 50,
      scrollShadowColor: accentColor,
      rows: rows,
      visibleScrollbar: true,
    );
  }

  @override
  Widget build(BuildContext context) {
    print(widget.data.values.first.keys);
    return Container(
      padding: const EdgeInsets.all(8.0),
      margin: const EdgeInsets.all(20),
      decoration: const BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.all(Radius.circular(10)),
      ),
      child: Flex(
        direction: Axis.vertical,
        mainAxisSize: MainAxisSize.min,
        children: [
          Flexible(
            child: SizedBox(
              width: double.infinity,
                height: 400,
                child: _buildTable()
            ),
          )
        ],
      ),
    );
  }

  Icon _setIcon(double value) {
    if (value == 1.0) {
      return const Icon(
        Icons.check_circle_outline_outlined,
        color: Colors.green,
        size: 20,
        weight: 5,
      );
    } else {
      return const Icon(
        Icons.block_outlined,
        color: Colors.red,
        size: 20,
        weight: 5,
      );
    }
  }

}

What am I missing?

rickypid commented 6 months ago

Hello @valiant-09,

If you need to modify the values after having built the table, you need to use the controller. You can find an example here. I hope this solves your problem.