Column drag and drop in Flutter Data Grid
18 Nov 201818 minutes to read
The SfDataGrid enables columns to be dragged and dropped by setting the SfDataGrid.allowColumnsDragging property to true and returning true from the SfDataGrid.onColumnDragging callback. During the column-dragging process, a drag feedback widget is displayed. By utilizing the SfDataGrid.onColumnDragging callback, you can handle drag and drop operations to reorder columns dynamically.
The DataGrid provides the rearranged index of the dragged column, indicating its new position after being dropped. Inside the onColumnDragging callback, you can utilize this index to reorder the columns to the desired position. This allows you to handle the column reordering directly within the callback at the sample level.
Prerequisites
The following code example demonstrates the basic setup required for column drag and drop functionality:
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
class Employee {
Employee(this.id, this.name, this.designation, this.salary);
final int id;
final String name;
final String designation;
final int salary;
dynamic operator [](String key) {
switch (key) {
case 'id':
return id;
case 'name':
return name;
case 'designation':
return designation;
case 'salary':
return salary;
default:
return '';
}
}
}Enable column drag and drop
The following code example shows how to enable column drag and drop functionality:
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: '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 Data Grid')),
body: SfDataGrid(
source: employeeDataSource,
columnWidthMode: ColumnWidthMode.fill,
allowColumnsDragging: true,
columns: columns,
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 List<Employee> employees,
required this.columns,
}) {
_employees = employees;
buildDataGridRows();
}
late List<Employee> _employees;
late List<GridColumn> columns;
late List<DataGridRow> dataGridRows;
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();
}
@override
List<DataGridRow> get rows => dataGridRows;
@override
DataGridRowAdapter? buildRow(DataGridRow row) {
return DataGridRowAdapter(
cells: row.getCells().map<Widget>((dataGridCell) {
return Container(
alignment: Alignment.center,
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Text(dataGridCell.value.toString()),
);
}).toList(),
);
}
void refreshDataGrid() {
notifyListeners();
}
}
Note:
- To reorder the columns in the DataGrid, create an instance variable to hold the columns and then assign that instance to the SfDataGrid.columns property instead of directly assigning a list literal. This allows you to reorder the collection within the callback, maintaining the desired column order.
- After reordering columns, rebuild the rows based on the updated columns collection by calling
buildDataGridRows()andnotifyListeners(). This is necessary because the column index may change after reordering. By rebuilding the rows, you ensure that the row data aligns correctly with the reordered columns.- Download the complete sample application from GitHub.
onColumnDragging callback
The SfDataGrid.onColumnDragging callback is triggered during column drag operations. This callback provides the following properties in the DataGridColumnDragDetails:
- from: The index of the currently dragging column. Use this to identify which column is being moved.
- to: The index where the column will be dropped. This is null during drag updates and populated when the column is dropped.
-
action: Indicates the drag action as a DataGridColumnDragAction enum. The
updateaction fires while dragging, anddroppedfires when the column is released. - offset: The current offset of the dragging column during the drag operation. Use this to calculate the drag position if needed.
Cancel the column dropping for a specific column
You can cancel the column dropping at a specific target column by returning false from the SfDataGrid.onColumnDragging callback. This allows you to prevent columns from being dropped at certain positions or restrict specific columns from being dropped.
In the following example, columns cannot be dropped at index 2 (the third column position):
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Syncfusion Flutter Data Grid')),
body: SfDataGrid(
source: employeeDataSource,
allowColumnsDragging: true,
columns: columns,
onColumnDragging: (DataGridColumnDragDetails details) {
// Prevent dropping at column index 2
if (details.action == DataGridColumnDragAction.update &&
details.to == 2) {
return false;
}
// Handle the drop action
if (details.action == DataGridColumnDragAction.dropped &&
details.to != null &&
details.from >= 0 &&
details.from < columns.length) {
final GridColumn rearrangeColumn = columns[details.from];
columns.removeAt(details.from);
columns.insert(details.to!, rearrangeColumn);
employeeDataSource.buildDataGridRows();
employeeDataSource.notifyListeners();
}
return true;
},
),
);
}Changing the feedback widget
The DataGrid allows you to customize the feedback widget displayed during column dragging by using the SfDataGrid.columnDragFeedbackBuilder builder. This builder is called during drag operations and allows you to return a custom widget that represents the dragged column.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Syncfusion Flutter Data Grid')),
body: SfDataGrid(
source: employeeDataSource,
allowColumnsDragging: true,
columns: columns,
columnDragFeedbackBuilder: (BuildContext context, GridColumn column) {
return Container(
height: 50,
width: column.actualWidth,
color: Colors.teal[400],
child: const Center(
child: DefaultTextStyle(
style: TextStyle(
fontSize: 14,
color: Colors.yellow,
fontWeight: FontWeight.bold,
),
child: Text('Drag View'),
),
),
);
},
onColumnDragging: (DataGridColumnDragDetails details) {
if (details.action == DataGridColumnDragAction.dropped &&
details.to != null &&
details.from >= 0 &&
details.from < columns.length) {
final GridColumn rearrangeColumn = columns[details.from];
columns.removeAt(details.from);
columns.insert(details.to!, rearrangeColumn);
employeeDataSource.buildDataGridRows();
employeeDataSource.notifyListeners();
}
return true;
},
),
);
}
Drag indicator customization
The color and thickness of the drag indicator displayed during column dragging can be customized using the SfDataGridThemeData.columnDragIndicatorColor and SfDataGridThemeData.columnDragIndicatorStrokeWidth properties. These properties are available in the syncfusion_flutter_core package through the SfDataGridTheme widget.
Note:
- The
SfDataGridThemeDataandSfDataGridThemeclasses are available in thesyncfusion_flutter_corepackage.- Import the theme package:
import 'package:syncfusion_flutter_core/theme.dart';
The following code demonstrates how to customize the drag indicator appearance:
import 'package:syncfusion_flutter_core/theme.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Syncfusion Flutter Data Grid')),
body: SfDataGridTheme(
data: SfDataGridThemeData(
columnDragIndicatorColor: Colors.pink,
columnDragIndicatorStrokeWidth: 3,
),
child: SfDataGrid(
source: employeeDataSource,
allowColumnsDragging: true,
columns: columns,
onColumnDragging: (DataGridColumnDragDetails details) {
if (details.action == DataGridColumnDragAction.dropped &&
details.to != null &&
details.from >= 0 &&
details.from < columns.length) {
final GridColumn rearrangeColumn = columns[details.from];
columns.removeAt(details.from);
columns.insert(details.to!, rearrangeColumn);
employeeDataSource.buildDataGridRows();
employeeDataSource.notifyListeners();
}
return true;
},
),
),
);
}