grid_sheet 2.0.3 copy "grid_sheet: ^2.0.3" to clipboard
grid_sheet: ^2.0.3 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';

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

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

  @override
  State<GridSheetApp> createState() => _GridSheetAppState();
}

class _GridSheetAppState extends State<GridSheetApp> {
  ThemeMode _themeMode = ThemeMode.light;

  void _toggleTheme() {
    setState(() {
      _themeMode =
          _themeMode == ThemeMode.light ? ThemeMode.dark : ThemeMode.light;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'GridSheet Example',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        useMaterial3: true,
        fontFamily: 'Inter',
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.blue,
          brightness: Brightness.light,
        ),
      ),
      darkTheme: ThemeData(
        useMaterial3: true,
        fontFamily: 'Inter',
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.blue,
          brightness: Brightness.dark,
        ),
      ),
      themeMode: _themeMode,
      home: Scaffold(
        floatingActionButton: FloatingActionButton(
          onPressed: _toggleTheme,
          tooltip: _themeMode == ThemeMode.light
              ? 'Switch to dark mode'
              : 'Switch to light mode',
          child: Icon(
            _themeMode == ThemeMode.light
                ? Icons.dark_mode_outlined
                : Icons.light_mode_outlined,
          ),
        ),
        body: const 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: GridSheetConfiguration(
        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');
        });
      },
      onCellValueChanged: (event) {
        log(
          '${event.title}: ${event.oldValue} → ${event.newValue}',
          name: 'GridSheetTableDemo',
        );
      },
    );
  }

  _mockData() {
    _columns = [
      'NAME',
      'DEPARTMENT',
      'ROLE',
      'STATUS',
      'REMOTE',
      'JOIN_YEAR',
      'SALARY',
      'BONUS',
      'REMARKS',
    ];
    _columnActualNames = {
      for (var col in _columns) col: col.replaceAll(' ', '').toUpperCase(),
    };
    _columnVisibility = {
      for (int i = 0; i < _columns.length; i++) _columns[i]: true,
    };
    _columnTypes = {
      'NAME': GridSheetColumnType.text,
      'DEPARTMENT': GridSheetColumnType.text,
      'ROLE': GridSheetColumnType.text,
      'STATUS': GridSheetColumnType.dropdown,
      'REMOTE': GridSheetColumnType.boolean,
      'JOIN_YEAR': GridSheetColumnType.integer,
      'SALARY': GridSheetColumnType.double,
      'BONUS': GridSheetColumnType.formula,
      'REMARKS': GridSheetColumnType.text,
    };
    _columnWidths = {
      'NAME': 160,
      'DEPARTMENT': 140,
      'ROLE': 180,
      'STATUS': 120,
      'REMOTE': 100,
      'JOIN_YEAR': 100,
      'SALARY': 110,
      'BONUS': 130,
      'REMARKS': 200,
    };
    _rows = [
      [
        'Alice Johnson',
        'Engineering',
        'Software Engineer',
        'Active',
        true,
        2021,
        95000.0,
        '=G1 * 0.1',
        null
      ],
      [
        'Bob Smith',
        'Engineering',
        'Senior Engineer',
        'Active',
        false,
        2019,
        118000.0,
        '=SUM(G1:G3)',
        null
      ],
      [
        'Carol Davis',
        'Engineering',
        'Software Engineer',
        'On Leave',
        true,
        2022,
        89000.0,
        '=G3 * 0.1',
        null
      ],
      [
        'David Lee',
        'Sales',
        'Sales Manager',
        'Active',
        false,
        2018,
        102000.0,
        null,
        'Exceeded quarterly target'
      ],
      [
        'Emma Wilson',
        'Sales',
        'Account Executive',
        'Active',
        true,
        2023,
        76000.0,
        '=G5 * 0.1',
        null
      ],
      [
        'Frank Miller',
        'Sales',
        'Account Executive',
        'Inactive',
        false,
        2020,
        71000.0,
        null,
        null
      ],
      [
        'Grace Kim',
        'Marketing',
        'Marketing Specialist',
        'Active',
        true,
        2022,
        68000.0,
        '=G7 * 0.1',
        null
      ],
      [
        'Henry Chen',
        'Marketing',
        'Marketing Manager',
        'Active',
        false,
        2017,
        99000.0,
        '=AVERAGE(G4:G7)',
        null
      ],
      [
        'Ivy Patel',
        'HR',
        'HR Coordinator',
        'Active',
        true,
        2021,
        62000.0,
        null,
        null
      ],
      [
        'Jack Brown',
        'HR',
        'HR Manager',
        'On Leave',
        false,
        2016,
        91000.0,
        '=G10 * 0.1',
        null
      ],
      [
        'Karen White',
        'Finance',
        'Financial Analyst',
        'Active',
        true,
        2020,
        84000.0,
        '=G11 * 0.1',
        null
      ],
      [
        'Liam Garcia',
        'Finance',
        'Finance Manager',
        'Active',
        false,
        2015,
        125000.0,
        '=MAX(G1:G11)',
        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() {
    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 == 'ROLE') {
        editableExpression = "DEPARTMENT == 'Engineering'";
      }

      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', 'On Leave'];
      }

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

  List<GridSheetRow> _buildRows() {
    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: 40,
      );

      return row;
    }).toList();
  }

  List<GridSheetConditionalFormatRule> getFormattingRules() {
    return [
      // Row scope: highlight the whole row for high earners.
      GridSheetConditionalFormatRule(
        name: 'SALARY',
        scope: GridSheetFormatScope.row,
        backgroundColorExpression: 'SALARY > 100000 ? "#C8E6C9" : null',
        textStyle:
            TextStyle(color: Color(0xFF1B5E20), fontWeight: FontWeight.bold),
      ),
      // Column scope: flag anyone currently on leave.
      GridSheetConditionalFormatRule(
        name: 'STATUS',
        scope: GridSheetFormatScope.column,
        backgroundColorExpression: 'STATUS == "On Leave" ? "#FFE0B2" : null',
        textStyle:
            TextStyle(color: Color(0xFFE65100), fontStyle: FontStyle.italic),
      ),
      // Cell scope: call out remote employees on just that one cell.
      GridSheetConditionalFormatRule(
        name: 'REMOTE',
        scope: GridSheetFormatScope.cell,
        backgroundColorExpression: 'REMOTE == true ? "#BBDEFB" : null',
        textStyle:
            TextStyle(color: Color(0xFF0D47A1), fontWeight: FontWeight.bold),
      ),
    ];
  }
}
3
likes
160
points
762
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