Selection in Flutter DataGrid (SfDataGrid)
7 Jul 202624 minutes to read
This section explains how to enable selection in the Datagrid; modes, properties, and callbacks involved in selection and customizations available for selection.
The Datagrid allows you to select a specific row or group of rows either programmatically or by touch interactions. To enable selection, set the selectionMode property of the SfDataGrid to a value other than none. The default value is none. SfDataGrid has different selection modes to perform the selection operation as follows.
Note:
- The rows property must be initialized in the source. The
rowsis the collection ofDataGridRowto populate the rows in DataGrid.- Import the SelectionMode enum from the
syncfusion_flutter_datagridpackage to use different selection modes in your application.
Selection modes
| Modes | Description |
|---|---|
| none | Disables selection and no rows can be selected. This is the default value. |
| single | Allows selection of a single row only. Upon selecting the next row, the selection in the previous row is cleared. |
| multiple | Allows selection of more than one row. Selection is not cleared when selecting more than one row. When you click on a selected row for the second time, the selection is cleared. |
| singleDeselect | Allows selection of only a single row. However, upon tapping the row again, the selection is cleared. Similar to single mode, upon selecting the next row, the selection in the previous row is cleared. |
Current cell navigation
Keyboard navigation through the cells and rows is determined based on the navigationMode property. The GridNavigationMode.cell allows you to navigate between the cells in a row and between the rows. The GridNavigationMode.row allows you to navigate between the rows.
@override
Widget build(BuildContext context) {
return Scaffold(
body: SfDataGrid(
source: _employeeDataSource,
columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'ID',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Name',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'designation',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Designation',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'salary',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'Salary',
overflow: TextOverflow.ellipsis,
))),
],
selectionMode: SelectionMode.single,
navigationMode: GridNavigationMode.cell,
),
);
}
Single row selection
It allows you to select only one row. For example, you have selected a row. Now if you select some other row, the previous row selection will be cleared. Hence it is a single row selection mode.
@override
Widget build(BuildContext context) {
return Scaffold(
body: SfDataGrid(
source: _employeeDataSource,
columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'ID',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Name',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'designation',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Designation',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'salary',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'Salary',
overflow: TextOverflow.ellipsis,
))),
],
selectionMode: SelectionMode.single));
}
Multiple row selection
The SfDataGrid allows you to select multiple rows by setting the selectionMode property as multiple, where you can select multiple rows by clicking on SfDataGrid and also using the key modifiers.
When using multiple, you can select multiple rows by pressing the key modifiers Shift + Down and Shift + Up.
@override
Widget build(BuildContext context) {
return Scaffold(
body: SfDataGrid(
source: _employeeDataSource,
columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'ID',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Name',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'designation',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Designation',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'salary',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'Salary',
overflow: TextOverflow.ellipsis,
))),
],
selectionMode: SelectionMode.multiple));
}
Note: When the
selectionModeismultiple, multiple rows can be selected or deselected by clicking the respective rows. In multiple selections, pressing the navigation keys will move the current cell alone. The rows can be selected or deselected by pressing the Space key.
Single deselect row selection
The singleDeselect mode allows selection of only one row at a time. Unlike the single mode, tapping a selected row again will deselect it. Selecting a different row will clear the previous selection.
@override
Widget build(BuildContext context) {
return Scaffold(
body: SfDataGrid(
source: _employeeDataSource,
columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text('ID', overflow: TextOverflow.ellipsis),
),
),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text('Name', overflow: TextOverflow.ellipsis),
),
),
GridColumn(
columnName: 'designation',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text('Designation', overflow: TextOverflow.ellipsis),
),
),
GridColumn(
columnName: 'salary',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text('Salary', overflow: TextOverflow.ellipsis),
),
),
],
selectionMode: SelectionMode.singleDeselect,
),
);
}Disable selection
The selection can be disabled by setting the selectionMode property as none.
@override
Widget build(BuildContext context) {
return Scaffold(
body: SfDataGrid(
source: _employeeDataSource,
columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'ID',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Name',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'designation',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Designation',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'salary',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'Salary',
overflow: TextOverflow.ellipsis,
))),
],
selectionMode: SelectionMode.none));
}Selection on a particular row can be disabled by handling the onCurrentCellActivating callback.
Note: You cannot select the header row of SfDataGrid.
Getting selected rows
Get the information of the selected rows by using the controller property. Create an instance of the DataGridController and set it to the controller property. The selectedRow property returns the selected DataGridRow and the selectedIndex property returns the index of the selectedRow in SfDataGrid. The selectedRow denotes the last selected row in multiple selections.
Note: DataGridController objects are expected to be long-lived, not re-created with each build. Instantiate the controller at the class level in your State class to maintain its state across widget rebuilds.
final DataGridController _dataGridController = DataGridController();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: [
TextButton(
child: Text('Get Selection Information'),
onPressed: () {
//SelectedIndex
var _selectedIndex = _dataGridController.selectedIndex;
//SelectedRow
var _selectedRow = _dataGridController.selectedRow;
//SelectedRows
var _selectedRows = _dataGridController.selectedRows;
print(_selectedIndex);
print(_selectedRow);
print(_selectedRows);
}),
Expanded(
child: SfDataGrid(
source: _employeeDataSource,
columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'ID',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Name',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'designation',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Designation',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'salary',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'Salary',
overflow: TextOverflow.ellipsis,
))),
],
controller: _dataGridController,
selectionMode: SelectionMode.multiple))
]));
}Programmatic selection
You can select rows programmatically by setting the DataGridController.selectedIndex, DataGridController.selectedRow, or DataGridController.selectedRows property based on the selection mode.
When the selection mode is single, you can select a row programmatically in two ways: by setting the row index to the DataGridController.selectedIndex property, or by setting the DataGridRow to be selected to the DataGridController.selectedRow property.
The following code example shows how to select a row using selectedIndex,
final DataGridController _dataGridController = DataGridController();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: [
TextButton(
child: Text('Set Selection'),
onPressed: () {
//SelectedIndex
_dataGridController.selectedIndex = 4;
}),
Expanded(
child: SfDataGrid(
source: _employeeDataSource,
columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'ID',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Name',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'designation',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Designation',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'salary',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'Salary',
overflow: TextOverflow.ellipsis,
))),
],
controller: _dataGridController,
selectionMode: SelectionMode.single))
]));
}The following code example shows how to select a row using selectedRow,
late EmployeeDataSource _employeeDataSource;
final DataGridController _dataGridController = DataGridController();
List<Employee> _employees = <Employee>[];
@override
void initState() {
super.initState();
_employees = getEmployeeData();
_employeeDataSource = EmployeeDataSource(employees: _employees);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: [
TextButton(
child: Text('Set Selection'),
onPressed: () {
//SelectedRow
_dataGridController.selectedRow = _employeeDataSource.dataGridRows[3];
}),
Expanded(
child: SfDataGrid(
source: _employeeDataSource,
columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'ID',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Name',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'designation',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Designation',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'salary',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'Salary',
overflow: TextOverflow.ellipsis,
))),
],
controller: _dataGridController,
selectionMode: SelectionMode.single))
]));
}Multiple rows can be selected by adding a collection of DataGridRow to the selectedRows property.
late EmployeeDataSource _employeeDataSource;
final DataGridController _dataGridController = DataGridController();
List<Employee> _employees = <Employee>[];
@override
void initState() {
super.initState();
_employees = getEmployeeData();
_employeeDataSource = EmployeeDataSource(employees: _employees);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: [
TextButton(
child: Text('Set Selection'),
onPressed: () {
//SelectedRows
_dataGridController.selectedRows = [
_employeeDataSource.dataGridRows[1],
_employeeDataSource.dataGridRows[3],
_employeeDataSource.dataGridRows[6],
];
}),
Expanded(
child: SfDataGrid(
source: _employeeDataSource,
columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'ID',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Name',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'designation',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Designation',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'salary',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'Salary',
overflow: TextOverflow.ellipsis,
))),
],
controller: _dataGridController,
selectionMode: SelectionMode.multiple))
]));
}
Get the current cell
The current cell information such as row index, and column index can be retrieved using the currentCell property of DataGridController.
final DataGridController _dataGridController = DataGridController();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: [
TextButton(
child: Text('Get current cell'),
onPressed: () {
var _currentCell = _dataGridController.currentCell;
print(_currentCell);
}),
Expanded(
child: SfDataGrid(
source: _employeeDataSource,
columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'ID',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Name',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'designation',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Designation',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'salary',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'Salary',
overflow: TextOverflow.ellipsis,
))),
],
controller: _dataGridController,
selectionMode: SelectionMode.single,
navigationMode: GridNavigationMode.cell))
]));
}Process current cell
The CurrentCell can be moved to a particular cell by using the moveCurrentCellTo method in DataGridController.
final DataGridController _dataGridController = DataGridController();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: [
TextButton(
child: Text('Move current cell'),
onPressed: () {
_dataGridController.moveCurrentCellTo(RowColumnIndex(6, 3));
}),
Expanded(
child: SfDataGrid(
source: _employeeDataSource,
columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'ID',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Name',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'designation',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Designation',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'salary',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'Salary',
overflow: TextOverflow.ellipsis,
))),
],
controller: _dataGridController,
selectionMode: SelectionMode.single,
navigationMode: GridNavigationMode.cell))
]));
}Clear selection
DataGrid allows you to clear the selection applied in the grid rows by setting the DataGridController.selectedIndex to -1 or DataGridController.selectedRow to null when the selectionMode property is in single or singleDeselect. When the selectionMode property is in multiple, clear the selection from grid rows by setting the DataGridController.selectedRows to empty.
The following code example shows how to clear selection when the selectionMode property is in single or singleDeselect.
final DataGridController _dataGridController = DataGridController();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: [
TextButton(
child: Text('Clear Selection'),
onPressed: () {
_dataGridController.selectedIndex = -1;
//or
//this._dataGridController.selectedRow = null;
}),
Expanded(
child: SfDataGrid(
source: _employeeDataSource,
columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'ID',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Name',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'designation',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Designation',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'salary',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'Salary',
overflow: TextOverflow.ellipsis,
))),
],
controller: _dataGridController,
selectionMode: SelectionMode.single))
]));
}The following code example shows how to clear selection when the selectionMode property is in multiple.
final DataGridController _dataGridController = DataGridController();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: [
TextButton(
child: Text('Clear Selection'),
onPressed: () {
_dataGridController.selectedRows = [];
}),
Expanded(
child: SfDataGrid(
source: _employeeDataSource,
columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'ID',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Name',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'designation',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Designation',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'salary',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'Salary',
overflow: TextOverflow.ellipsis,
))),
],
controller: _dataGridController,
selectionMode: SelectionMode.multiple))
]));
}Note: Selected rows and selections will be cleared whenever the
dataSourceis changed at runtime.
Keyboard behavior
| Key or KeyCombinations | Description |
|---|---|
| DownArrow | Moves CurrentCell directly under the active current cell. If the CurrentCell is in the last row, pressing DownArrow does nothing. |
| UpArrow | Moves the CurrentCell directly above the active current cell. If the CurrentCell is in the first row, pressing UpArrow does nothing. |
| LeftArrow | Moves the current cell to the previous to the active current cell. If the CurrentCell is in the first cell, pressing LeftArrow does nothing. If the focused row is a group header, the group will be collapsed when it is in an expanded state. |
| RightArrow | Moves the current cell to next to the active current cell. If the CurrentCell is in the last cell, pressing RightArrow does nothing. If the focused row is a group header, the group will expand when it is in a collapsed state. |
| Home / Ctrl + LeftArrow | Moves the current cell to the first cell of the current row. |
| End / Ctrl + RightArrow | Moves the current cell to the last cell of the current row. |
| PageDown | The SfDataGrid will be scrolled to the next set of rows that are not displayed in the view, including the row that is partially displayed and the current cell is set to the last row. |
| PageUp | The SfDataGrid will be scrolled to the previous set of rows that are not displayed in the view, including the row that is partially displayed and the current cell is set to the first row. |
| Tab | Moves the current cell to next to the active current cell. If the active current cell is the last cell of the current row, the focus will move to the first cell of the row next to the current row. If the active current cell is the last cell of the last row, the focus will be moved to the next widget in the tab order of the parent container. |
| Shift + Tab | Moves the current cell to the previous to the active current cell. If the active current cell is the first cell of the current row, the current cell will move to the last cell of the row previous to the current row. If the active current cell is the first cell of the first row, the focus will be moved to the previous widget in the tab order of the parent container. |
| Ctrl + DownArrow | Moves the current cell to the current column of the last row. |
| Ctrl + UpArrow | Moves the current cell to the current column of the first row. |
| Ctrl + Home | Moves the current cell to the first cell of the first row. |
| Ctrl + End | Moves the current cell to the last cell of the last row. |
| Enter | The current cell will be moved to the next focused row of the same column. |
| Ctrl + A | All rows or cells will be selected. |
| F2 | If the DataGrid.AllowEditing property is true and the GridColumn.AllowEditing property is true for the current column, the current cell enters into edit mode. |
| Esc | If the current cell is in edit mode, call the DataGridSource.onCellCancelEdit method to revert the current changes and ends the editing. |
Callbacks
The Datagrid provides the following callbacks for selection:
-
onSelectionChanging: This callback is raised before a row is selected at execution time, allowing you to cancel the selection action by returningfalse. -
onSelectionChanged: This callback is raised after the row is successfully selected.
The following are the parameters of the onSelectionChanging and onSelectionChanged callbacks:
- newItems: Gets a collection of the
DataGridRowobjects added to the selection. - oldItems: Gets a collection of the
DataGridRowobjects removed from the selection.
The following example shows how to cancel the selection when selecting a row that contains the designation of the Manager.
late EmployeeDataSource _employeeDataSource;
List<Employee> _employees = <Employee>[];
@override
void initState() {
super.initState();
_employees = getEmployeeData();
_employeeDataSource = EmployeeDataSource(employees: _employees);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SfDataGrid(
source: _employeeDataSource,
columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text('ID', overflow: TextOverflow.ellipsis),
),
),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text('Name', overflow: TextOverflow.ellipsis),
),
),
GridColumn(
columnName: 'designation',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text('Designation', overflow: TextOverflow.ellipsis),
),
),
GridColumn(
columnName: 'salary',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text('Salary', overflow: TextOverflow.ellipsis),
),
),
],
selectionMode: SelectionMode.single,
onSelectionChanging:
(List<DataGridRow> addedRows, List<DataGridRow> removedRows) {
if (addedRows.isNotEmpty) {
final index = _employeeDataSource._employeeData.indexOf(
addedRows.last,
);
if (index >= 0 && index < _employees.length) {
Employee employee = _employees[index];
if (employee.designation == 'Manager') {
return false;
}
}
}
return true;
},
onSelectionChanged:
(List<DataGridRow> addedRows, List<DataGridRow> removedRows) {
// Handle selection change
},
),
);
}-
onCurrentCellActivating: This callback is raised before the current cell applies to the corresponding grid cell of the selecting row. So, it allows canceling the selection action by returningfalse.If the return is false, the selection will not apply, and also,onSelectionChanging,onSelectionChangedandonCurrentCellActivatedare not called. -
onCurrentCellActivated: This callback is raised after the current cell is applied in the grid cell on the selecting row.
The following are the parameters of the onCurrentCellActivating and onCurrentCellActivated callbacks:
- newRowColumnIndex: Gets the current RowColumnIndex of the current cell, containing row and column indices.
- oldRowColumnIndex: Gets the previous RowColumnIndex of the current cell, containing row and column indices.
@override
Widget build(BuildContext context) {
return Scaffold(
body: SfDataGrid(
source: _employeeDataSource,
columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'ID',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Name',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'designation',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Designation',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'salary',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'Salary',
overflow: TextOverflow.ellipsis,
))),
],
selectionMode: SelectionMode.single,
navigationMode: GridNavigationMode.cell,
onCurrentCellActivating: (RowColumnIndex currentRowColumnIndex,
RowColumnIndex previousRowColumnIndex) {
if (currentRowColumnIndex.rowIndex == 2 &&
currentRowColumnIndex.columnIndex == 3) {
return false;
}
return true;
},
onCurrentCellActivated: (RowColumnIndex currentRowColumnIndex,
RowColumnIndex previousRowColumnIndex) {
// apply your logic
},
));
}Cell Tap callbacks
The Datagrid provides the following callbacks to handle interactions with the cells. These callbacks are triggered after onSelectionChanging and onSelectionChanged callbacks.
- onCellTap : Called when a tap on a cell has occurred.
- onCellDoubleTap : Called when a cell is tapped with a primary button twice in quick succession.
- onCellLongPress : Called when a long press gesture with a primary button has been recognized for a cell.
- onCellSecondaryTap : Called when a tap on a cell has occurred with a secondary button.
@override
Widget build(BuildContext context) {
return Scaffold(
body: SfDataGrid(
source: _employeeDataSource,
columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'ID',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Name',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'designation',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Designation',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'salary',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'Salary',
overflow: TextOverflow.ellipsis,
))),
],
onCellTap: (DataGridCellTapDetails details) {
print(details);
},
onCellDoubleTap: (DataGridCellDoubleTapDetails details) {
print(details);
},
onCellLongPress: (DataGridCellLongPressDetails details) {
print(details);
},
onCellSecondaryTap: (DataGridCellTapDetails details) {
print(details);
}));
}Getting row details
To retrieve the details of a row in the DataGrid, use the controller property. Create an instance of the DataGridController and assign it to the controller property of the DataGrid. To obtain the details of a row, use the getRowDetails method from the controller, providing the index as the parameter. This method returns a DataGridRowDetails, which includes the following properties:
-
rowType – Returns the type of the row (e.g., dataRow, headerRow).
-
dataGridRow – Provides the DataGridRow corresponding to the specified index.
-
isSelected – Indicates whether the row is currently selected.
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
TextButton(
onPressed: () {
DataGridRowDetails? details =
_dataGridController.getRowDetails(4);
if (details != null) {
print(details.rowType);
print(details.dataGridRow);
print(details.isSelected);
}
},
child: Text('Get row details')),
Expanded(
child: SfDataGrid(
source: employeeDataSource,
controller: _dataGridController,
columns: <GridColumn>[
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.all(16.0),
alignment: Alignment.center,
child: Text('ID'),
),
),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.all(8.0),
alignment: Alignment.center,
child: Text('Name'),
),
),
GridColumn(
columnName: 'designation',
label: Container(
padding: EdgeInsets.all(8.0),
alignment: Alignment.center,
child: Text('Designation'),
),
),
GridColumn(
columnName: 'salary',
label: Container(
padding: EdgeInsets.all(8.0),
alignment: Alignment.center,
child: Text('Salary'),
),
),
],
),
),
],
),
);
}Customizing selection behavior
To perform custom actions beyond the default keyboard behavior mentioned in the keyboard behavior table, create a custom selection manager by overriding the handleKeyEvent() method of the RowSelectionManager class and assign it to the SfDataGrid.selectionManager property.
Note: Import services and foundation packages from Flutter to use
LogicalKeyboardKeyandHardwareKeyboard.
The following example demonstrates how to implement a custom action for the Ctrl + A key combination:
import 'package:flutter/services.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
final CustomSelectionManager _customSelectionManager = CustomSelectionManager();
@override
Widget build(BuildContext context) {
return Scaffold(
body: SfDataGrid(
source: _employeeDataSource,
columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'ID',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Name',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'designation',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Designation',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'salary',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'Salary',
overflow: TextOverflow.ellipsis,
))),
],
selectionMode: SelectionMode.multiple,
selectionManager: _customSelectionManager,
));
}
class CustomSelectionManager extends RowSelectionManager {
@override
void handleKeyEvent(KeyEvent keyEvent) {
if (keyEvent.logicalKey == LogicalKeyboardKey.keyA) {
if (HardwareKeyboard.instance.isControlPressed) {
// Apply custom logic for Ctrl+A
return;
}
}
super.handleKeyEvent(keyEvent);
}
}Change Enter key behavior
By default, pressing the Enter key moves the current cell to the next focused row of the same column. You can customize this behavior by overriding the handleKeyEvent() method in a custom RowSelectionManager.
import 'package:flutter/services.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
final CustomSelectionManager _customSelectionManager =
CustomSelectionManager();
@override
Widget build(BuildContext context) {
return Scaffold(
body: SfDataGrid(
source: _employeeDataSource,
columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text('ID', overflow: TextOverflow.ellipsis),
),
),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text('Name', overflow: TextOverflow.ellipsis),
),
),
GridColumn(
columnName: 'designation',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text('Designation', overflow: TextOverflow.ellipsis),
),
),
GridColumn(
columnName: 'salary',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text('Salary', overflow: TextOverflow.ellipsis),
),
),
],
selectionMode: SelectionMode.multiple,
navigationMode: GridNavigationMode.cell,
selectionManager: _customSelectionManager,
),
);
}
class CustomSelectionManager extends RowSelectionManager {
@override
Future<void> handleKeyEvent(KeyEvent keyEvent) async {
if (keyEvent.logicalKey == LogicalKeyboardKey.enter) {
// Apply custom logic for Enter key
return;
}
super.handleKeyEvent(keyEvent);
}
}Appearance
You can customize the appearance of selected rows and the current cell by using the SfDataGridTheme and SfDataGridThemeData classes. All styles such as selectionColor and DataGridCurrentCellStyle are available in the syncfusion_flutter_core package.
Note: Import
package:syncfusion_flutter_core/theme.dartto access the theming classes.
Selection
Customize the selection background color using the selectionColor property of the SfDataGridThemeData.
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
import 'package:syncfusion_flutter_core/theme.dart';
final DataGridController _dataGridController = DataGridController();
late EmployeeDataSource _employeeDataSource;
@override
void initState() {
super.initState();
_employeeDataSource = EmployeeDataSource(_dataGridController);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SfDataGridTheme(
data: SfDataGridThemeData(selectionColor: Colors.red),
child: SfDataGrid(
source: _employeeDataSource,
columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'ID',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Name',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'designation',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Designation',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'salary',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'Salary',
overflow: TextOverflow.ellipsis,
))),
],
selectionMode: SelectionMode.multiple,
)));
}
class EmployeeDataSource extends DataGridSource {
EmployeeDataSource(this.dataGridController) {
dataGridRows = _employees
.map<DataGridRow>((dataGridRow) => DataGridRow(cells: [
DataGridCell<int>(columnName: 'id', value: dataGridRow.id),
DataGridCell<String>(columnName: 'name', value: dataGridRow.name),
DataGridCell<String>(
columnName: 'designation', value: dataGridRow.designation),
DataGridCell<int>(
columnName: 'salary', value: dataGridRow.salary),
]))
.toList();
}
final DataGridController dataGridController;
List<DataGridRow> dataGridRows = [];
@override
List<DataGridRow> get rows => dataGridRows;
@override
DataGridRowAdapter? buildRow(DataGridRow row) {
TextStyle? getSelectionTextStyle() {
return dataGridController.selectedRows.contains(row)
? TextStyle(
fontFamily: 'Raleway',
fontWeight: FontWeight.w300,
color: Colors.white,
)
: null;
}
return DataGridRowAdapter(
cells: row.getCells().map<Widget>((dataGridCell) {
return Container(
color: Colors.transparent,
alignment: (dataGridCell.columnName == 'id' ||
dataGridCell.columnName == 'salary')
? Alignment.centerRight
: Alignment.centerLeft,
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: Text(
dataGridCell.value.toString(),
overflow: TextOverflow.ellipsis,
style: getSelectionTextStyle(),
),
);
}).toList());
}
}
Current cell
Customize the current cell border color and thickness using the currentCellStyle property of SfDataGridThemeData. The current cell border is displayed when navigationMode is set to GridNavigationMode.cell.
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
import 'package:syncfusion_flutter_core/theme.dart';
@override
Widget build(BuildContext context) {
return Scaffold(
body: SfDataGridTheme(
data: SfDataGridThemeData(
currentCellStyle: DataGridCurrentCellStyle(
borderWidth: 2, borderColor: Colors.pinkAccent)),
child: SfDataGrid(
source: _employeeDataSource,
columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'ID',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Name',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'designation',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Designation',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'salary',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'Salary',
overflow: TextOverflow.ellipsis,
))),
],
selectionMode: SelectionMode.multiple,
navigationMode: GridNavigationMode.cell,
)));
}
Note: When navigationMode is set to GridNavigationMode.row, the
currentCellStyleproperty customizes the current row border’s color instead of individual cell borders.