Hello,
I'm trying to customize the SFDataGrid sortIcons.
I've seen the help here : https://help.syncfusion.com/flutter/datagrid/sorting#set-a-custom-sorting-icon
I'm trying to have no icon when the column can be sorted, but not sorted.
And to have an icon when the colum is sorted.
Like this :
Problem : it seems to keep a space for the "null" icon when the column is not sorted, so that, the header text is not properly centered.
Any ideas to better implement this ?
Thanks
Hi Julien,
If you set the SizedBox or Container widget for the unsorted icon, the widget doesn’t keep any space. The space you are experiencing is the icon outer padding value which we set in our source. As per your requirement, you can remove the padding of the iconsOuterPadding using ColumnSizer class. You can override the ColumnSizer.iconsOuterPadding property and set the padding value as 0 and then create the instance for the custom class and set it in the SfDataGrid.columnSizer property. This will allow you to remove the padding space of the icon in the header cell. You can set the icon with the padding value when sorting by setting the icon with padding. We have prepared a sample for that. Please check the following sample and code snippet.
final CustomColumnSizer _customColumnSizer = CustomColumnSizer();
@override void initState() { super.initState(); _employees = getEmployeeData(); _employeeDataSource = EmployeeDataSource(_employees); }
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Flutter SfDataGrid'), ), body: SfDataGridTheme( data: SfDataGridThemeData( sortIcon: Builder( builder: (context) { Widget? icon; String columnName = ''; context.visitAncestorElements((element) { if (element is GridHeaderCellElement) { columnName = element.column.columnName; } return true; }); var column = _employeeDataSource.sortedColumns .where((element) => element.name == columnName) .firstOrNull; if (column != null) { if (column.sortDirection == DataGridSortDirection.ascending) { icon = const Padding( padding: EdgeInsets.symmetric(horizontal: 4), child: Icon(Icons.arrow_circle_up_rounded, size: 16)); } else if (column.sortDirection == DataGridSortDirection.descending) { icon = const Padding( padding: EdgeInsets.symmetric(horizontal: 4), child: Icon(Icons.arrow_circle_down_rounded, size: 16)); } } return icon ?? const SizedBox(); }, ), ), child: SfDataGrid( source: _employeeDataSource, columnSizer: _customColumnSizer, allowSorting: true, columns: getColumns, columnWidthMode: ColumnWidthMode.fill, ), ), ); }
In ColumnSizer Class:
class CustomColumnSizer extends ColumnSizer { EdgeInsetsGeometry _iconsOuterPadding = const EdgeInsets.all(0);
@override EdgeInsetsGeometry get iconsOuterPadding => _iconsOuterPadding;
@override set iconsOuterPadding(EdgeInsetsGeometry value) { _iconsOuterPadding = value; } } |
We hope this helps. Please let us know if you require any further assistance on this.
Regards,
Tamilarasan
Thanks for your answer, which resolves the problem perfectly.
Another question :
The 1st click on the column header, makes an ascending sort
The 2nd click makes a descending sort
The 3rd click makes an ascending sort
etc...
Is it possible to have this behaviour :
The 1st click on the column header, makes an ascending sort
The 2nd click makes a descending sort
The 3rd click restores the default sort (like no header columns have been clicked)
Thanks !
Julien,
Based on your requirement, you can achieve this by using the SfDataGrid.allowTriStateSorting property. If you set this property to true, the SfDataGrid will allow you to unsort the data in the original order by clicking the header again after sorting to descending order. The sorting in each column iterates through three sort states: ascending, descending, and unsort. Please check the following code snippet.
SfDataGrid( source: _employeeDataSource, allowSorting: true, allowTriStateSorting: true, columns: getColumns, columnWidthMode: ColumnWidthMode.fill, ), |
We have already provided the detailed information about the tristate sorting in below UG link,
UG: https://help.syncfusion.com/flutter/datagrid/sorting#tri-state-sorting
Hello, and thanks for this answer.
You are right the allowTriStateSorting works perfectly, except for one thing.
I programmatically sort the columns on the 1st one at start.
When I sort then unsort the data on another column, the default sort becomes that of the filling order, and not the sort on the 1st column.
Is it possible to listen to an event when the user unsort the data ? So that I programmatically sort the columns on the 1st one, as I need.
Thanks !
Julien,
According to your requirement, the sort method in the DataGridSource class can help you achieve your goal. This method is called when columns are sorted. If the sortedColumns collection is empty, you can add the corresponding column to it, enabling you to achieve your requirement. However, this condition doesn't support tristate sorting for the first column because the sortedColumns collection is empty in unsorted order for the first column. To resolve this issue, you can identify the first column by using a bool property. In the SfDataGrid.onCellTap callback, set the bool property to true when the first column is tapped, and modify the condition in the sort method to add the column to the sortedColumns collection only if the collection is empty and the tapped column is not the first column. Please refer to the code snippet below for a better understanding. I have attached a simple sample. Please check the following sample and code snippet.
bool isFirstColumnTapped = false;
class SfDataGridDemoState extends State<SfDataGridDemo> {
@override void initState() { super.initState(); _employees = getEmployeeData(); _employeeDataSource = EmployeeDataSource(_employees); _employeeDataSource.sortedColumns.add(const SortColumnDetails( name: 'id', sortDirection: DataGridSortDirection.descending)); }
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Flutter SfDataGrid'), ), body: SfDataGridTheme( data: SfDataGridThemeData( sortIcon: Builder( builder: (context) { Widget? icon; String columnName = ''; context.visitAncestorElements((element) { if (element is GridHeaderCellElement) { columnName = element.column.columnName; } return true; }); var column = _employeeDataSource.sortedColumns .where((element) => element.name == columnName) .firstOrNull; if (column != null) { if (column.sortDirection == DataGridSortDirection.ascending) { icon = const Padding( padding: EdgeInsets.symmetric(horizontal: 4), child: Icon(Icons.arrow_circle_up_rounded, size: 16)); } else if (column.sortDirection == DataGridSortDirection.descending) { icon = const Padding( padding: EdgeInsets.symmetric(horizontal: 4), child: Icon(Icons.arrow_circle_down_rounded, size: 16)); } } return icon ?? const SizedBox(); }, ), ), child: SfDataGrid( source: _employeeDataSource, columnSizer: _customColumnSizer, onCellTap: (details) { if (details.rowColumnIndex.columnIndex == 0 && details.rowColumnIndex.rowIndex == 0) { isFirstColumnTapped = true; } else { isFirstColumnTapped = false; } }, allowSorting: true, allowTriStateSorting: true, columns: getColumns, columnWidthMode: ColumnWidthMode.fill, ), ), ); } }
class EmployeeDataSource extends DataGridSource {
… @override void sort() { if (!isFirstColumnTapped && sortedColumns.isEmpty) { sortedColumns.add(const SortColumnDetails( name: 'id', sortDirection: DataGridSortDirection.descending)); } super.sort(); } } |