grid_sheet 1.2.1 copy "grid_sheet: ^1.2.1" to clipboard
grid_sheet: ^1.2.1 copied to clipboard

A Flutter DataGrid/DataTable with minimal configuration and powerful features like filtering, formulas, pagination, editing, frozen columns, CRUD, and full customization.

example/lib/main.dart

import 'dart:developer';

import 'package:flutter/material.dart';
import 'package:grid_sheet/grid_sheet.dart';

void main() {
  runApp(GridSheetApp());
}

class GridSheetApp extends StatelessWidget {
  const GridSheetApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Grid Sheet Package',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        useMaterial3: true,
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.blue,
          brightness: Brightness.light,
        ),
      ),
      darkTheme: ThemeData(
        useMaterial3: true,
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.blue,
          brightness: Brightness.dark,
        ),
      ),
      themeMode: ThemeMode.system,
      home: Scaffold(
        body: GridSheetExample(),
      ),
    );
  }
}

class GridSheetExample extends StatefulWidget {
  const GridSheetExample({super.key});

  @override
  State<GridSheetExample> createState() => _GridSheetExampleState();
}

class _GridSheetExampleState extends State<GridSheetExample> {
  late final GridSheetManager gridManager;

  late List<String> _columns;
  late List<List<dynamic>> _rows;

  late Map<String, double> _columnWidths;
  late Map<String, bool> _columnVisibility;
  late Map<String, String> _columnActualNames;
  late Map<String, GridSheetColumnType> _columnTypes;

  @override
  void initState() {
    super.initState();

    _mockData();
  }

  @override
  void dispose() {
    super.dispose();
  }

  List<GridSheetColumn> get columns => _getColumns();
  List<GridSheetRow> get rows => _getRows();

  @override
  Widget build(BuildContext context) {
    // Build style configuration based on current theme
    final styleConfiguration = _buildStyleConfiguration(context);

    return GridSheet(
      columns: columns,
      rows: rows,
      configuration: GridSheetLayoutConfiguration(
        enableMultiSelection: true,
        enableCellSelection: true,
        enableColumnSelection: true,
        enableRowSelectionOnFirstColumnTap: true,
        enableReorder: true,
        rowsPerPage: 15,
      ),
      styleConfiguration: styleConfiguration,
      conditionalFormatRules: getFormattingRules(),
      onLoaded: (event) {
        gridManager = event.gridManager;
        log('Table initialized!', name: 'GridSheetTableDemo');
      },
      onColumnsSelected: (event) {
        event.selectedColumnsData.forEach((columnName, values) {
          log(
            '$columnName: ${values.length} values',
            name: 'GridSheetTableDemo',
          );
        });
      },
      onRowsSelected: (event) {
        for (final rowMap in event.selectedRowsData) {
          log('Row data: $rowMap', name: 'GridSheetTableDemo');
        }
      },
      onCellsSelected: (event) {
        event.selectedCellsData.forEach((columnName, values) {
          log('$columnName: $values', name: 'GridSheetTableDemo');
        });
      },
      onCellValueChange: (event) {
        log(
          '${event.columnName}: ${event.oldValue} → ${event.newValue}',
          name: 'GridSheetTableDemo',
        );
      },
    );
  }

  _mockData() {
    _columns = [
      'COUNTRY_NAME',
      'REGION',
      'CATEGORY_TYPE',
      'AVAILABLE',
      'YEAR',
      'SALES',
      'FORMULA_COL',
      'EMPTY_COL'
    ];
    _columnActualNames = {
      for (var col in _columns) col: col.replaceAll(' ', '').toUpperCase(),
    };
    _columnVisibility = {
      for (int i = 0; i < _columns.length; i++) _columns[i]: true,
    };
    _columnTypes = {
      'COUNTRY_NAME': GridSheetColumnType.text,
      'REGION': GridSheetColumnType.text,
      'CATEGORY_TYPE': GridSheetColumnType.text,
      'AVAILABLE': GridSheetColumnType.boolean,
      'YEAR': GridSheetColumnType.double,
      'SALES': GridSheetColumnType.double,
      'FORMULA_COL': GridSheetColumnType.formula,
      'EMPTY_COL': GridSheetColumnType.integer,
    };
    _columnWidths = {
      'COUNTRY_NAME': 150,
      'REGION': 150,
      'CATEGORY_TYPE': 150,
      'AVAILABLE': 100,
      'YEAR': 100,
      'SALES': 100,
      'FORMULA_COL': 200,
      'EMPTY_COL': 100,
    };
    _rows = [
      ['Canada', 'North', 'Furniture', true, 2024, 700.0, '=F1 * 2', null],
      ['Canada', 'North', 'Office', true, 2023, 500.0, '=SUM(E1:F3)', null],
      ['India', 'East', 'Furniture', false, 2025, 1200.0, '=F3 + E4', null],
      ['India', 'East', 'Office', true, 2021, 800.0, null, null],
      [
        'US',
        'South',
        'Office',
        true,
        2022,
        400.0,
        '=F * 2',
        null
      ], //'=F * 2' (current row f-cell * 2)
      ['US', 'South', 'Furniture', true, 2025, 200.0, '=SALES4 + YEAR4', null],
    ];
  }

  GridSheetStyleConfiguration _buildStyleConfiguration(BuildContext context) {
    final colorScheme = Theme.of(context).colorScheme;
    final isDark = Theme.of(context).brightness == Brightness.dark;

    return GridSheetStyleConfiguration(
      gridBackgroundColor: colorScheme.surface,
      headerColor: colorScheme.surfaceContainerHighest,
      filterColor: colorScheme.surfaceContainerHighest,
      rowColor: colorScheme.surface,
      evenRowColor: isDark
          ? colorScheme.surfaceContainerLow
          : colorScheme.surfaceContainerLowest,
      oddRowColor: colorScheme.surface,
      selectionColor: colorScheme.primary,
      gridBorderColor: colorScheme.outlineVariant,
      rowBorderColor: colorScheme.outlineVariant,
      columnBorderColor: colorScheme.outlineVariant,
    );
  }

  List<GridSheetColumn> _getColumns({int frozenColumnCount = 0}) {
    return _columns.asMap().entries.map((e) {
      final column = e.value;
      final index = e.key;
      final key = '${GridSheetConstants.columnCopyKeyStartsWith}$index';

      // Read from configurations
      bool isEditable = true;
      bool noEditMode = false;

      final actualName = _columnActualNames[column] ?? column;
      final display = _columnVisibility[column] ?? false;
      final maxWidth = _columnWidths[column] ?? 120.0;
      final type = _columnTypes[column] ?? GridSheetColumnType.text;

      String? editableExpression = '';
      if (actualName == 'CATEGORY_TYPE') {
        editableExpression = "COUNTRY_NAME == 'Canada'";
      }

      TextAlign alignment = TextAlign.left;
      if (type == GridSheetColumnType.integer ||
          type == GridSheetColumnType.double) {
        alignment = TextAlign.right;
      } else if (type == GridSheetColumnType.datetime) {
        noEditMode = true;
      }

      return GridSheetColumn(
        key: ValueKey<String>(key),
        title: column,
        name: actualName,
        type: type,
        width: maxWidth,
        visible: display,
        textAlign: alignment,
        frozen: index < frozenColumnCount,
        editable: isEditable,
        conditionalEditExpression: editableExpression,
        index: index,
        resize: true,
        sortable: true,
        noTextControllerWidget: noEditMode,
      );
    }).toList();
  }

  List<GridSheetRow> _getRows({double rowHeight = 30.0}) {
    return _rows.asMap().entries.map((e) {
      final index = e.key;
      final rowData = e.value;
      final key = '${GridSheetConstants.rowKeyStartsWith}$index';

      final row = GridSheetRow(
        key: ValueKey<String>(key),
        index: index,
        data: rowData,
        height: rowHeight,
      );

      return row;
    }).toList();
  }

  List<GridSheetConditionalFormatRule> getFormattingRules() {
    return [
      GridSheetConditionalFormatRule(
        name: 'COUNTRY_NAME',
        expression: "YEAR > 2024",
        scope: GridSheetFormatScope.row,
        backgroundColor: Colors.red,
      ),
      GridSheetConditionalFormatRule(
        name: 'REGION',
        expression: "CATEGORY_TYPE == 'Furniture'",
        scope: GridSheetFormatScope.column,
        backgroundColor: Colors.green,
      ),
      GridSheetConditionalFormatRule(
        name: 'CATEGORY_TYPE',
        expression: "SALES > 700",
        scope: GridSheetFormatScope.cell,
        backgroundColor: Colors.orange,
      ),
    ];
  }
}
1
likes
160
points
443
downloads

Publisher

unverified uploader

Weekly Downloads

A Flutter DataGrid/DataTable with minimal configuration and powerful features like filtering, formulas, pagination, editing, frozen columns, CRUD, and full customization.

Homepage
View/report issues

Topics

#data-table #data-grid #table #excel #spreadsheet

Documentation

API reference

License

MIT (license)

Dependencies

expressions, flutter

More

Packages that depend on grid_sheet