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

A powerful Flutter DataGrid/DataTable for large datasets, offering Excel-like features and fully customizable cells — ready with minimal setup. See README for full features

example/lib/main.dart

import 'dart:developer';

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

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

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

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder<ThemeMode>(
      valueListenable: appThemeMode,
      builder: (_, themeMode, __) => MaterialApp(
        title: 'Grid Sheet Package Demo',
        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,
        home: const 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();
  }

  @override
  Widget build(BuildContext context) {
    final styleConfiguration = _buildStyleConfiguration(context);

    return GridSheet(
      columns: _buildColumns(),
      rows: _buildRows(),
      configuration: GridSheetLayoutConfiguration(
        enableMultiSelection: true,
        enableCellSelection: true,
        enableColumnSelection: true,
        enableRowSelectionOnFirstColumnTap: true,
        enableColumnReorder: true,
        enableRowReorder: true,
        rowsPerPage: 30,
        enableRowResize: true,
      ),
      autofillConfiguration: GridSheetAutoFillConfiguration(enabled: true),
      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',
      'STATUS',
      '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,
      'STATUS': GridSheetColumnType.dropdown,
      '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,
      'STATUS': 130,
      'AVAILABLE': 100,
      'YEAR': 100,
      'SALES': 100,
      'FORMULA_COL': 200,
      'EMPTY_COL': 100,
    };
    _rows = [
      [
        'Canada',
        'North',
        'Furniture',
        'Active',
        true,
        2024,
        700.0,
        '=G1 * 2',
        null
      ],
      [
        'Canada',
        'North',
        'Office',
        'Pending',
        true,
        2023,
        500.0,
        '=SUM(F1:G3)',
        null
      ],
      [
        'India',
        'East',
        'Furniture',
        'Inactive',
        false,
        2025,
        1200.0,
        '=G3 + F4',
        null
      ],
      ['India', 'East', 'Office', 'Active', true, 2021, 800.0, null, null],
      ['US', 'South', 'Office', 'Pending', true, 2022, 400.0, '=G * 2', null],
      [
        'US',
        'South',
        'Furniture',
        'Active',
        true,
        2025,
        200.0,
        '=SALES5 + YEAR5',
        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> _buildColumns({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;
      }

      List<String>? dropdownOptions;
      if (type == GridSheetColumnType.dropdown && actualName == 'STATUS') {
        dropdownOptions = ['Active', 'Inactive', 'Pending'];
      }

      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,
        dropdownOptions: dropdownOptions,
        index: index,
        resize: true,
        sortable: true,
        noTextControllerWidget: noEditMode,
      );
    }).toList();
  }

  List<GridSheetRow> _buildRows({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',
        scope: GridSheetFormatScope.row,
        backgroundColorExpression: 'YEAR > 2024 ? "#FFCDD2" : null',
        textStyle:
            TextStyle(color: Color(0xFFB71C1C), fontWeight: FontWeight.bold),
      ),
      GridSheetConditionalFormatRule(
        name: 'REGION',
        scope: GridSheetFormatScope.column,
        backgroundColorExpression:
            'CATEGORY_TYPE == "Furniture" ? "#C8E6C9" : null',
        textStyle:
            TextStyle(color: Color(0xFF1B5E20), fontWeight: FontWeight.bold),
      ),
      GridSheetConditionalFormatRule(
        name: 'CATEGORY_TYPE',
        scope: GridSheetFormatScope.cell,
        backgroundColorExpression: 'SALES > 700 ? "#FFE0B2" : null',
        textStyle:
            TextStyle(color: Color(0xFFE65100), fontStyle: FontStyle.italic),
      ),
    ];
  }
}
3
likes
150
points
334
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A powerful Flutter DataGrid/DataTable for large datasets, offering Excel-like features and fully customizable cells — ready with minimal setup. See README for full features

Homepage
View/report issues

Topics

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

License

MIT (license)

Dependencies

expressions, flutter

More

Packages that depend on grid_sheet