Syncfusion Flutter DataGrid: How to Enable Drag and Drop Column Reordering and Column Resizing

84 Views Asked by At

Syncfusion Flutter DataGrid: How to Enable Drag and Drop Column Reordering and Column Resizing

I am unable to create Syncfusion's Flutter DataGrid widget with drag-and-drop column and resize column functionalities. I have attempted to do so, but it is not giving me the expected output, as the resizing of columns is not working.


import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';

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

/// The application that contains datagrid on it.
class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Syncfusion DataGrid Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const MyHomePage(),
    );
  }
}

/// The home page of the application which hosts the datagrid. 

class MyHomePage extends StatefulWidget {
  /// Creates the home page.

  const MyHomePage({Key? key}) : super(key: key);

  @override
  MyHomePageState createState() => MyHomePageState();
}

class MyHomePageState extends State<MyHomePage> {
  List<Employee> employees = <Employee>[];
  late List<GridColumn> columns;
  late EmployeeDataSource employeeDataSource;

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

    columns = getColumns;
    employees = getEmployeeData();
    employeeDataSource =
        EmployeeDataSource(employees: employees, columns: columns);
  }

  List<GridColumn> get getColumns {
    return <GridColumn>[
      GridColumn(
          columnName: 'id',
          width: columnWidths['id']!,
          label: Container(
              padding: const EdgeInsets.all(16.0),
              alignment: Alignment.center,
              child: const Text(
                'ID',
              ))),
      GridColumn(
          columnName: 'name',
          width: columnWidths['name']!,
          label: Container(
              padding: const EdgeInsets.all(8.0),
              alignment: Alignment.center,
              child: const Text('Name'))),
      GridColumn(
          columnName: 'designation',
          width: columnWidths['designation']!,
          label: Container(
              padding: const EdgeInsets.all(8.0),
              alignment: Alignment.center,
              child: const Text(
                'Designation',
                overflow: TextOverflow.ellipsis,
              ))),
      GridColumn(
          columnName: 'email',
          width: columnWidths['email']!,
          label: Container(
              padding: const EdgeInsets.all(8.0),
              alignment: Alignment.center,
              child: const Text(
                'Email',
                overflow: TextOverflow.ellipsis,
              ))),
      GridColumn(
          columnName: 'salary',
          width: columnWidths['salary']!,
          label: Container(
              padding: const EdgeInsets.all(8.0),
              alignment: Alignment.center,
              child: const Text('Salary'))),
    ];
  }

  late Map<String, double> columnWidths = {
    'id': double.nan,
    'name': double.nan,
    'designation': double.nan,
    'email': double.nan,
    'salary': double.nan,
  };

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Syncfusion Flutter DataGrid')),
      body: SfDataGrid(
        source: employeeDataSource,
        columnWidthMode: ColumnWidthMode.fill,

        allowColumnsDragging: true,
        columns: columns,
        columnResizeMode: ColumnResizeMode.onResizeEnd,
        allowColumnsResizing: true,
        //  defaultColumnWidth: colwidth,
        onColumnResizeUpdate: (ColumnResizeUpdateDetails details) {
          setState(() {
            columnWidths[details.column.columnName] = details.width;
          });
          return true;
        },
        onColumnDragging: (DataGridColumnDragDetails details) {
          if (details.action == DataGridColumnDragAction.dropped &&
              details.to != null) {
            final GridColumn rearrangeColumn = columns[details.from];
            columns.removeAt(details.from);
            columns.insert(details.to!, rearrangeColumn);
            employeeDataSource.buildDataGridRows();
            employeeDataSource.refreshDataGrid();
          }
          return true;
        },
      ),
    );
  }
}

class EmployeeDataSource extends DataGridSource {
  EmployeeDataSource({required this.employees, required this.columns}) {
    buildDataGridRows();
  }

  void buildDataGridRows() {
    dataGridRows = employees.map<DataGridRow>((employee) {
      return DataGridRow(
          cells: columns.map<DataGridCell>((column) {
        return DataGridCell(
          columnName: column.columnName,
          value: employee[column.columnName],
        );
      }).toList());
    }).toList();
  }

  List<Employee> employees = [];

  List<GridColumn> columns = [];

  List<DataGridRow> dataGridRows = [];

  @override
  List<DataGridRow> get rows => dataGridRows;

  @override
  DataGridRowAdapter? buildRow(DataGridRow row) {
    return DataGridRowAdapter(
        cells: row.getCells().map((dataGridCell) {
      return Container(
          alignment: Alignment.center,
          padding: const EdgeInsets.symmetric(horizontal: 8.0),
          child: Text(
            dataGridCell.value.toString(),
          ));
    }).toList());
  }

  refreshDataGrid() {
    notifyListeners();
  }
}

/// Custom business object class which contains properties to hold the detailed
/// information about the employee which will be rendered in datagrid.
class Employee {
  /// Creates the employee class with required details.
  Employee(this.id, this.name, this.designation, this.email, this.salary);

  /// Id of an employee.
  final int id;

  /// Name of an employee.
  final String name;

  /// Designation of an employee.
  final String designation;

  final String email;

  /// Salary of an employee.
  final int salary;

  /// Overrides the indexing operator to provide access to specific properties of the  [Employee] class.
  operator [](Object? value) {
    if (value == 'id') {
      return id;
    } else if (value == 'name') {
      return name;
    } else if (value == 'designation') {
      return designation;
    } else if (value == 'email') {
      return email;
    } else if (value == 'salary') {
      return salary;
    } else {
      throw ArgumentError('Invalid property: $value');
    }
  }
}

List<Employee> getEmployeeData() {
  return [
    Employee(10001, 'Jack Anderson', 'Manager', '[email protected]', 120000),
    Employee(10002, 'Olivia Wilson', 'Developer', '[email protected]', 500000),
    Employee(10003, 'Emma Wilson', 'Developer', '[email protected]', 49000),
    Employee(10004, 'Thomas Hardy', 'Developer', '[email protected]', 48000),
    Employee(10005, 'Mia Garcia', 'Developer', '[email protected]', 47000),
    Employee(10006, 'John Smith', 'Developer', '[email protected]', 43000),
    Employee(10007, 'Maria Andres', 'Developer', '[email protected]', 41000),
    Employee(10008, 'Samuel Martinez', 'Developer', '[email protected]', 40000),
    Employee(10009, 'Hanna Moos', 'Developer', '[email protected]', 40000),
    Employee(10010, 'Amelia Young', 'Developer', '[email protected]', 39000),
    Employee(
        10011, 'Patricio Simpson', 'Developer', '[email protected]', 39000)
  ];
}

1

There are 1 best solutions below

0
Tamizh On BEST ANSWER

In scenarios where columns are managed within an object instance for drag and drop functionality, it is essential to update the corresponding column width within the instance.


import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';

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

/// The application that contains datagrid on it.
class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Syncfusion DataGrid Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const MyHomePage(),
    );
  }
}

/// The home page of the application which hosts the datagrid.

class MyHomePage extends StatefulWidget {
  /// Creates the home page.

  const MyHomePage({Key? key}) : super(key: key);

  @override
  MyHomePageState createState() => MyHomePageState();
}

class MyHomePageState extends State<MyHomePage> {
  List<Employee> employees = <Employee>[];
  late List<GridColumn> columns;
  late EmployeeDataSource employeeDataSource;

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

    columns = getColumns;
    employees = getEmployeeData();
    employeeDataSource =
        EmployeeDataSource(employees: employees, columns: columns);
  }

  List<GridColumn> get getColumns {
    return <GridColumn>[
      GridColumn(
          columnName: 'id',
          label: Container(
              padding: const EdgeInsets.all(16.0),
              alignment: Alignment.center,
              child: const Text(
                'ID',
              ))),
      GridColumn(
          columnName: 'name',
          label: Container(
              padding: const EdgeInsets.all(8.0),
              alignment: Alignment.center,
              child: const Text('Name'))),
      GridColumn(
          columnName: 'designation',
          label: Container(
              padding: const EdgeInsets.all(8.0),
              alignment: Alignment.center,
              child: const Text(
                'Designation',
                overflow: TextOverflow.ellipsis,
              ))),
      GridColumn(
          columnName: 'email',
          label: Container(
              padding: const EdgeInsets.all(8.0),
              alignment: Alignment.center,
              child: const Text(
                'Email',
                overflow: TextOverflow.ellipsis,
              ))),
      GridColumn(
          columnName: 'salary',
          label: Container(
              padding: const EdgeInsets.all(8.0),
              alignment: Alignment.center,
              child: const Text('Salary'))),
    ];
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Syncfusion Flutter DataGrid')),
      body: SfDataGrid(
        source: employeeDataSource,
        columnWidthMode: ColumnWidthMode.fill,

        allowColumnsDragging: true,
        columns: columns,
        columnResizeMode: ColumnResizeMode.onResizeEnd,
        allowColumnsResizing: true,
        //  defaultColumnWidth: colwidth,
        onColumnResizeUpdate: (ColumnResizeUpdateDetails details) {
          setState(() {
            int index = columns.indexOf(columns.firstWhere(
                (element) => element.columnName == details.column.columnName));

            columns[index] = GridColumn(
                columnName: details.column.columnName,
                width: details.width,
                label: details.column.label);
          });

          return true;
        },
        onColumnDragging: (DataGridColumnDragDetails details) {
          if (details.action == DataGridColumnDragAction.dropped &&
              details.to != null) {
            final GridColumn rearrangeColumn = columns[details.from];
            columns.removeAt(details.from);
            columns.insert(details.to!, rearrangeColumn);
            employeeDataSource.buildDataGridRows();
            employeeDataSource.refreshDataGrid();
          }
          return true;
        },
      ),
    );
  }
}

class EmployeeDataSource extends DataGridSource {
  EmployeeDataSource({required this.employees, required this.columns}) {
    buildDataGridRows();
  }

  void buildDataGridRows() {
    dataGridRows = employees.map<DataGridRow>((employee) {
      return DataGridRow(
          cells: columns.map<DataGridCell>((column) {
        return DataGridCell(
          columnName: column.columnName,
          value: employee[column.columnName],
        );
      }).toList());
    }).toList();
  }

  List<Employee> employees = [];

  List<GridColumn> columns = [];

  List<DataGridRow> dataGridRows = [];

  @override
  List<DataGridRow> get rows => dataGridRows;

  @override
  DataGridRowAdapter? buildRow(DataGridRow row) {
    return DataGridRowAdapter(
        cells: row.getCells().map((dataGridCell) {
      return Container(
          alignment: Alignment.center,
          padding: const EdgeInsets.symmetric(horizontal: 8.0),
          child: Text(
            dataGridCell.value.toString(),
          ));
    }).toList());
  }

  refreshDataGrid() {
    notifyListeners();
  }
}

/// Custom business object class which contains properties to hold the detailed
/// information about the employee which will be rendered in datagrid.
class Employee {
  /// Creates the employee class with required details.
  Employee(this.id, this.name, this.designation, this.email, this.salary);

  /// Id of an employee.
  final int id;

  /// Name of an employee.
  final String name;

  /// Designation of an employee.
  final String designation;

  final String email;

  /// Salary of an employee.
  final int salary;

  /// Overrides the indexing operator to provide access to specific properties of the  [Employee] class.
  operator [](Object? value) {
    if (value == 'id') {
      return id;
    } else if (value == 'name') {
      return name;
    } else if (value == 'designation') {
      return designation;
    } else if (value == 'email') {
      return email;
    } else if (value == 'salary') {
      return salary;
    } else {
      throw ArgumentError('Invalid property: $value');
    }
  }
}

List<Employee> getEmployeeData() {
  return [
    Employee(10001, 'Jack Anderson', 'Manager', '[email protected]', 120000),
    Employee(10002, 'Olivia Wilson', 'Developer', '[email protected]', 500000),
    Employee(10003, 'Emma Wilson', 'Developer', '[email protected]', 49000),
    Employee(10004, 'Thomas Hardy', 'Developer', '[email protected]', 48000),
    Employee(10005, 'Mia Garcia', 'Developer', '[email protected]', 47000),
    Employee(10006, 'John Smith', 'Developer', '[email protected]', 43000),
    Employee(10007, 'Maria Andres', 'Developer', '[email protected]', 41000),
    Employee(10008, 'Samuel Martinez', 'Developer', '[email protected]', 40000),
    Employee(10009, 'Hanna Moos', 'Developer', '[email protected]', 40000),
    Employee(10010, 'Amelia Young', 'Developer', '[email protected]', 39000),
    Employee(
        10011, 'Patricio Simpson', 'Developer', '[email protected]', 39000)
  ];
}