We use cookies to give you the best experience on our website. If you continue to browse, then you agree to our privacy policy and cookie policy. Image for the cookie policy date

Customize SFDataGrid sortIcons

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 :

child: SfDataGridTheme(
data: SfDataGridThemeData(
selectionColor: Colors.blue,
rowHoverColor: Colors.yellow,
filterIcon: Container(),
sortIcon: Builder(
builder: (context) {
Widget? icon;
String columnName = '';
context.visitAncestorElements((element) {
if (element is GridHeaderCellElement) {
columnName = element.column.columnName;
}
return true;
});
var column = widget
._ligneDataSource.sortedColumns
.where((element) =>
element.name == columnName)
.firstOrNull;
if (column != null) {
if (column.sortDirection ==
DataGridSortDirection.ascending) {
icon = const Icon(Icons.arrow_upward,
size: 8);
} else if (column.sortDirection ==
DataGridSortDirection.descending) {
icon = const Icon(Icons.arrow_downward,
size: 8);
}
}
return icon ?? Container();
},
),
),


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



5 Replies

TP Tamilarasan Paranthaman Syncfusion Team February 21, 2023 12:18 PM UTC

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


Attachment: sample_624103c5.zip


JU Julien February 21, 2023 02:27 PM UTC

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 !




TP Tamilarasan Paranthaman Syncfusion Team February 22, 2023 09:04 AM UTC

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



JU Julien February 22, 2023 09:17 AM UTC

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 !



TP Tamilarasan Paranthaman Syncfusion Team February 23, 2023 12:30 PM UTC

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();

  }

}   



Attachment: Sample_75dcce46.zip

Loader.
Up arrow icon