diff --git a/Flutter/datagrid/accessibility.md b/Flutter/datagrid/accessibility.md index 8c3f93f25..a5032e715 100644 --- a/Flutter/datagrid/accessibility.md +++ b/Flutter/datagrid/accessibility.md @@ -9,9 +9,15 @@ documentation: ug # Accessibility in Flutter DataGrid (SfDataGrid) +The [SfDataGrid](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid-class.html) widget is designed with comprehensive accessibility features to ensure all users, including those using assistive technologies, can interact with data effectively. This section covers built-in accessibility support and best practices for implementing an accessible data grid experience. + ## Screen reader support -The [SfDataGrid](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid-class.html) can be accessed easily by screen readers in the following ways on Android and iOS platforms: +The SfDataGrid supports screen readers through the following interactions on Android and iOS platforms: + +* Cell contents can be read by tapping the required cell. +* Adjacent cell content can be navigated by swiping left or right. +* Scroll the DataGrid vertically and horizontally by dragging with two fingers. * Cell contents can be read by tapping the required cell. * Read adjacent cell content by swiping right or left. @@ -19,24 +25,27 @@ The [SfDataGrid](https://pub.dev/documentation/syncfusion_flutter_datagrid/lates ## Sufficient contrast -The [SfDataGrid](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid-class.html) provides sufficient color contrast to make cell content more readable. Use the following properties to customize the appearance of the DataGrid elements: +The [SfDataGrid](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid-class.html) provides sufficient color contrast to make cell content more readable and compliant with WCAG 2.1 AA standards. Customize the appearance of DataGrid elements using the following properties: -* [currentCellStyle](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/currentCellStyle.html) -* [frozenPaneElevation](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/frozenPaneElevation.html) -* [frozenPaneLineColor](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/frozenPaneLineColor.html) -* [gridLineColor](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/gridLineColor.html) -* [headerColor](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/headerColor.html) -* [headerHoverColor](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/headerHoverColor.html) -* [selectionColor](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/selectionColor.html) -* [sortIconColor](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/sortIconColor.html) +* [`currentCellStyle`](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/currentCellStyle.html) — Styling for the currently selected cell +* [`frozenPaneElevation`](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/frozenPaneElevation.html) — Shadow depth for frozen panes +* [`frozenPaneLineColor`](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/frozenPaneLineColor.html) — Border color for frozen pane dividers +* [`gridLineColor`](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/gridLineColor.html) — Color of grid lines between cells +* [`headerColor`](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/headerColor.html) — Background color of column headers +* [`headerHoverColor`](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/headerHoverColor.html) — Header background color on hover +* [`selectionColor`](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/selectionColor.html) — Background color for selected cells +* [`sortIconColor`](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/sortIconColor.html) — Color of sort indicator icons ## Large fonts -Since [SfDataGrid](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid-class.html) receives widgets from the user for each cell, the font size in those widgets will automatically adjust based on OS settings in Android and iOS platforms. To ensure cell content remains clearly visible, the row heights in the DataGrid will automatically adjust based on the `MediaQueryData.textScaleFactor`. +Since [SfDataGrid](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid-class.html) receives widgets from the user for each cell, the font size in those widgets automatically adjusts based on OS text scale settings on Android and iOS platforms. To ensure cell content remains clearly visible, row heights adjust automatically based on the [`MediaQueryData.textScaleFactor`](https://api.flutter.dev/flutter/widgets/MediaQueryData/textScaleFactor.html). + +The following example demonstrates how to apply a custom text scale factor: {% tabs %} {% highlight Dart %} +import 'package:flutter/material.dart'; import 'package:syncfusion_flutter_datagrid/datagrid.dart'; @override @@ -54,8 +63,8 @@ Widget build(BuildContext context) { child: Text( 'ID', overflow: TextOverflow.ellipsis, - ) - ) + ), + ), ), GridColumn( columnName: 'name', @@ -65,8 +74,8 @@ Widget build(BuildContext context) { child: Text( 'Name', overflow: TextOverflow.ellipsis, - ) - ) + ), + ), ), GridColumn( columnName: 'salary', @@ -76,8 +85,8 @@ Widget build(BuildContext context) { child: Text( 'Salary', overflow: TextOverflow.ellipsis, - ) - ) + ), + ), ), GridColumn( columnName: 'designation', @@ -87,11 +96,11 @@ Widget build(BuildContext context) { child: Text( 'Designation', overflow: TextOverflow.ellipsis, - ) - ) - ) - ] - ) + ), + ), + ), + ], + ), ); } @@ -100,11 +109,77 @@ Widget build(BuildContext context) { ## Keyboard navigation -The [SfDataGrid](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid-class.html) provides keyboard navigation support when the [selectionMode](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/selectionMode.html) and [navigationMode](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/navigationMode.html) are enabled. Refer to this [link](https://help.syncfusion.com/flutter/datagrid/selection#keyboard-behavior) for supported keys and their purpose. +The [SfDataGrid](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid-class.html) supports keyboard navigation for enhanced accessibility and desktop usability. Enable keyboard navigation by configuring the [`selectionMode`](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/selectionMode.html) and [`navigationMode`](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/navigationMode.html) properties. + +**Supported keyboard interactions:** +* **Arrow keys** — Navigate between cells (up, down, left, right) +* **Tab/Shift+Tab** — Move focus to the next/previous cell +* **Enter** — Select/activate the current cell +* **Ctrl+Home** — Navigate to the first cell +* **Ctrl+End** — Navigate to the last cell +* **Page Up/Page Down** — Scroll vertically by one page + +For detailed keyboard behavior documentation, refer to the [keyboard behavior guide](https://help.syncfusion.com/flutter/datagrid/selection#keyboard-behavior). + +The following example enables keyboard navigation: + +{% tabs %} +{% highlight Dart %} + +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SfDataGrid( + source: _employeeDataSource, + selectionMode: SelectionMode.single, + navigationMode: GridNavigationMode.cell, + columns: [ + 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', overflow: TextOverflow.ellipsis), + ), + ), + GridColumn( + columnName: 'salary', + label: Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.center, + child: Text('Salary'), + ), + ), + ], + ), + ); + } + +{% endhighlight %} +{% endtabs %} ## Visual density -The row heights in [SfDataGrid](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid-class.html) will automatically adjust based on the [visualDensity](https://api.flutter.dev/flutter/material/ThemeData/visualDensity.html) property. +Row heights in [SfDataGrid](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid-class.html) automatically adjust based on the [`visualDensity`](https://api.flutter.dev/flutter/material/ThemeData/visualDensity.html) property. This allows you to create compact or spacious layouts that adapt to user preferences and device capabilities. {% tabs %} {% highlight Dart %} @@ -112,61 +187,51 @@ The row heights in [SfDataGrid](https://pub.dev/documentation/syncfusion_flutter import 'package:flutter/material.dart'; import 'package:syncfusion_flutter_datagrid/datagrid.dart'; -@override -Widget build(BuildContext context) { - return Theme( - data: ThemeData(visualDensity: VisualDensity.compact), - 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: 'salary', - label: Container( - padding: EdgeInsets.symmetric(horizontal: 16.0), - alignment: Alignment.centerRight, - child: Text( - 'Salary', - overflow: TextOverflow.ellipsis, - ) - ) + @override + Widget build(BuildContext context) { + return Scaffold( + body: Theme( + data: ThemeData(visualDensity: VisualDensity.compact), + 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: 'salary', + label: Container( + padding: EdgeInsets.symmetric(horizontal: 16.0), + alignment: Alignment.centerRight, + child: Text('Salary', 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: 'designation', - label: Container( - padding: EdgeInsets.symmetric(horizontal: 16.0), - alignment: Alignment.centerLeft, - child: Text( - 'Designation', - overflow: TextOverflow.ellipsis, - ) - ) - ) - ] - ) - ); -} + ), + ); + } {% endhighlight %} {% endtabs %} diff --git a/Flutter/datagrid/column-drag-and-drop.md b/Flutter/datagrid/column-drag-and-drop.md index b0fc87c5b..7ce93cf05 100644 --- a/Flutter/datagrid/column-drag-and-drop.md +++ b/Flutter/datagrid/column-drag-and-drop.md @@ -9,19 +9,113 @@ documentation: ug # Column drag and drop in Flutter DataGrid (SfDataGrid) -The SfDataGrid allows column header dragging and dropping by setting the [SfDataGrid.allowColumnsDragging](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/allowColumnsDragging.html) property to `true` and returning `true` from the [SfDataGrid.onColumnDragging](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/onColumnDragging.html) callback. During the column-dragging process, a drag feedback widget is displayed. By utilizing the `SfDataGrid.onColumnDragging` event, you can handle drag and drop operations according to your requirements. +The SfDataGrid enables columns to be dragged and dropped by setting the [SfDataGrid.allowColumnsDragging](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/allowColumnsDragging.html) property to `true` and returning `true` from the [SfDataGrid.onColumnDragging](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/onColumnDragging.html) 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 according to the desired position. This allows you to handle the column reordering directly within the callback at the sample level. +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: + +{% tabs %} +{% highlight Dart %} + +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 ''; + } + } +} + +{% endhighlight %} +{% endtabs %} + +## Enable column drag and drop + +The following code example shows how to enable column drag and drop functionality: {% tabs %} {% highlight Dart %} + List employees = []; + late List columns; + late EmployeeDataSource employeeDataSource; + + @override + void initState() { + super.initState(); + + columns = getColumns; + employees = getEmployeeData(); + employeeDataSource = EmployeeDataSource( + employees: employees, + columns: columns, + ); + } + + List get getColumns { + return [ + 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 DataGrid')), body: SfDataGrid( source: employeeDataSource, + columnWidthMode: ColumnWidthMode.fill, allowColumnsDragging: true, columns: columns, onColumnDragging: (DataGridColumnDragDetails details) { @@ -40,43 +134,48 @@ The DataGrid provides the rearranged index of the dragged column, indicating its } class EmployeeDataSource extends DataGridSource { - EmployeeDataSource({required this.employees, required this.columns}) { + EmployeeDataSource({ + required List employees, + required this.columns, + }) { + _employees = employees; buildDataGridRows(); } + late List _employees; + late List columns; + late List dataGridRows; + void buildDataGridRows() { - dataGridRows = employees.map((employee) { + dataGridRows = _employees.map((employee) { return DataGridRow( cells: columns.map((column) { return DataGridCell( columnName: column.columnName, value: employee[column.columnName], ); - }).toList()); + }).toList(), + ); }).toList(); } - List employees = []; - List columns = []; - List dataGridRows = []; - @override List get rows => dataGridRows; @override DataGridRowAdapter? buildRow(DataGridRow row) { return DataGridRowAdapter( - cells: row.getCells().map((dataGridCell) { + cells: row.getCells().map((dataGridCell) { return Container( alignment: Alignment.center, padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Text( - dataGridCell.value.toString(), - )); - }).toList()); + child: Text(dataGridCell.value.toString()), + ); + }).toList(), + ); } - refreshDataGrid() { + void refreshDataGrid() { notifyListeners(); } } @@ -86,25 +185,25 @@ class EmployeeDataSource extends DataGridSource { Flutter datagrid shows a checkbox filter in web platform ->**NOTE**: -* You can download the demo application from [GitHub](https://github.com/SyncfusionExamples/how-to-perform-column-drag-and-drop-in-flutter-datatable-sfdatagrid). -* To reorder the columns in the DataGrid, you should create an instance to hold the columns and then assign that instance to -the [SfDataGrid.columns](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/columns.html) property instead of directly assigning the list of GridColumn. This allows you to reorder the collection within the callback, maintaining the desired column order. -* Additionally, it is important to build the rows based on the columns collection after reordering. This is necessary because -the column index may change after the columns have been rearranged. By rebuilding the rows based on the updated columns collection, you ensure that the row data aligns correctly with the reordered columns. +> **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](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/columns.html) 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()` and `notifyListeners()`. 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](https://github.com/SyncfusionExamples/how-to-perform-column-drag-and-drop-in-flutter-datatable-sfdatagrid). ## onColumnDragging callback -The `SfDataGrid.onColumnDragging` callback is triggered when the column drags. This callback provides the following properties in the [DataGridColumnDragDetails](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridColumnDragDetails-class.html). +The [SfDataGrid.onColumnDragging](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/onColumnDragging.html) callback is triggered during column drag operations. This callback provides the following properties in the [DataGridColumnDragDetails](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridColumnDragDetails-class.html): -* [from](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridColumnDragDetails/from.html): Returns index of the currently dragging column. -* [to](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridColumnDragDetails/to.html): Returns index of the column after being dropped. -* [action](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridColumnDragDetails/action.html): Returns the column dragging details as the [DataGridColumnDragAction](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridColumnDragAction.html) enum. -* [offset](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridColumnDragDetails/offset.html): Returns the current offset of the dragging column. +* [from](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridColumnDragDetails/from.html): The index of the currently dragging column. Use this to identify which column is being moved. +* [to](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridColumnDragDetails/to.html): The index where the column will be dropped. This is null during drag updates and populated when the column is dropped. +* [action](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridColumnDragDetails/action.html): Indicates the drag action as a [DataGridColumnDragAction](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridColumnDragAction.html) enum. The `update` action fires while dragging, and `dropped` fires when the column is released. +* [offset](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridColumnDragDetails/offset.html): 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 column by returning `false` from the `SfDataGrid.onColumnDragging` callback. This allows you to restrict 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](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/onColumnDragging.html) 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): {% tabs %} {% highlight Dart %} @@ -118,17 +217,21 @@ You can cancel the column dropping at a specific column by returning `false` fro 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.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.refreshDataGrid(); + employeeDataSource.notifyListeners(); } return true; }, @@ -141,7 +244,7 @@ You can cancel the column dropping at a specific column by returning `false` fro ## Changing the feedback widget -The DataGrid allows you to change the drag feedback widget by returning a custom widget from the [SfDataGrid.columnDragFeedbackBuilder](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/columnDragFeedbackBuilder.html) builder. This allows you to change the drag feedback widget according to your requirements. +The DataGrid allows you to customize the feedback widget displayed during column dragging by using the [SfDataGrid.columnDragFeedbackBuilder](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/columnDragFeedbackBuilder.html) builder. This builder is called during drag operations and allows you to return a custom widget that represents the dragged column. {% tabs %} {% highlight Dart %} @@ -154,17 +257,18 @@ The DataGrid allows you to change the drag feedback widget by returning a custom source: employeeDataSource, allowColumnsDragging: true, columns: columns, - columnDragFeedbackBuilder: (context, column) { + columnDragFeedbackBuilder: (BuildContext context, GridColumn column) { return Container( height: 50, width: column.actualWidth, - color: Colors.grey, + color: Colors.teal[400], child: const Center( child: DefaultTextStyle( style: TextStyle( fontSize: 14, - color: Colors.pink, - fontWeight: FontWeight.bold), + color: Colors.yellow, + fontWeight: FontWeight.bold, + ), child: Text('Drag View'), ), ), @@ -172,12 +276,14 @@ The DataGrid allows you to change the drag feedback widget by returning a custom }, onColumnDragging: (DataGridColumnDragDetails details) { if (details.action == DataGridColumnDragAction.dropped && - details.to != null) { + 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.refreshDataGrid(); + employeeDataSource.notifyListeners(); } return true; }, @@ -192,22 +298,19 @@ The DataGrid allows you to change the drag feedback widget by returning a custom ## Drag indicator customization -The color and thickness of the drag indicator can be customized by the [SfDataGridThemeData.columnDragIndicatorColor](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/columnDragIndicatorColor.html) and [SfDataGridThemeData.columnDragIndicatorStrokeWidth](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/columnDragIndicatorStrokeWidth.html) properties. +The color and thickness of the drag indicator displayed during column dragging can be customized using the [SfDataGridThemeData.columnDragIndicatorColor](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/columnDragIndicatorColor.html) and [SfDataGridThemeData.columnDragIndicatorStrokeWidth](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/columnDragIndicatorStrokeWidth.html) properties. These properties are available in the `syncfusion_flutter_core` package through the [SfDataGridTheme](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridTheme-class.html) widget. -The `SfDataGridThemeData` and `SfDataGridTheme` classes are available in the `syncfusion_flutter_core` package. So, import the following file. +> **Note:** +>* The `SfDataGridThemeData` and `SfDataGridTheme` classes are available in the `syncfusion_flutter_core` package. +>* Import the theme package: `import 'package:syncfusion_flutter_core/theme.dart';` + +The following code demonstrates how to customize the drag indicator appearance: {% tabs %} {% highlight Dart %} import 'package:syncfusion_flutter_core/theme.dart'; - -{% endhighlight %} -{% endtabs %} - -The following code describes how to change the drag indicator color and thickness by using [SfDataGridTheme](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridTheme-class.html). - -{% tabs %} -{% highlight Dart %} +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; @override Widget build(BuildContext context) { @@ -216,19 +319,22 @@ The following code describes how to change the drag indicator color and thicknes body: SfDataGridTheme( data: SfDataGridThemeData( columnDragIndicatorColor: Colors.pink, - columnDragIndicatorStrokeWidth: 3), + columnDragIndicatorStrokeWidth: 3, + ), child: SfDataGrid( source: employeeDataSource, allowColumnsDragging: true, columns: columns, onColumnDragging: (DataGridColumnDragDetails details) { if (details.action == DataGridColumnDragAction.dropped && - details.to != null) { + 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.refreshDataGrid(); + employeeDataSource.notifyListeners(); } return true; }, diff --git a/Flutter/datagrid/column-types.md b/Flutter/datagrid/column-types.md index 36cb0c9e4..92b199a03 100644 --- a/Flutter/datagrid/column-types.md +++ b/Flutter/datagrid/column-types.md @@ -9,7 +9,7 @@ documentation: ug # Column Types in Flutter DataGrid (SfDataGrid) -[SfDataGrid](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid-class.html) provides support for loading any type of widget in each column. +[SfDataGrid](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid-class.html) provides support for loading any type of widget in each column. The `SfDataGrid` supports two main column types: `GridColumn` for standard data binding and a `Checkbox` column for row selection. This document covers the features and customization options available for each column type. ## GridColumn @@ -17,7 +17,7 @@ GridColumn is a class that provides base functionalities for all the column type ### Mapping column to a property -The column can be bound to a property in a data object using the [GridColumn.columnName](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn/columnName.html) property. The [label](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn/label.html) is used to display the required widget in a column header. +The column can be bound to a property in a data object using the [GridColumn.columnName](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn/columnName.html) property. The [label](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn/label.html) property is used to display the required widget in a column header. The `columnName` must match the property name in your data model for automatic data binding. {% tabs %} {% highlight Dart %} @@ -84,8 +84,7 @@ The column can be bound to a property in a data object using the [GridColumn.col [GridColumn.visible](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn/visible.html) property can be used to set a column as hidden. The default value of the `visible` property is true. ->**NOTE** ->Set the `visible` property to `false` instead of setting column width as `0` to hide a column. +> **Note:** Set the `visible` property to `false` instead of setting column width as `0` to hide a column. {% tabs %} {% highlight Dart %} @@ -151,10 +150,9 @@ The column can be bound to a property in a data object using the [GridColumn.col ### Set manual width for a column -[SfDataGrid](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid-class.html) allows you to customize the width of each [GridColumn](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn-class.html) in the [SfDataGrid.columns](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/columns.html) collection. To customize column width, use the [GridColumn.width](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn/width.html) property. By default, this property will not be assigned any value. The GridColumn renders in view based on the value of the [defaultColumnWidth](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/defaultColumnWidth.html) property. +[SfDataGrid](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid-class.html) allows you to customize the width of each [GridColumn](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn-class.html) in the [SfDataGrid.columns](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/columns.html) collection. To customize column width, use the [GridColumn.width](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn/width.html) property. Specify the width value in logical pixels. By default, this property will not be assigned any value, and the column renders based on the [SfDataGrid.defaultColumnWidth](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/defaultColumnWidth.html) property. ->**NOTE** ->Set the `visible` property to `false` instead of setting column width as `0` to hide a column. +> **Note:** Set the `visible` property to `false` instead of setting column width as `0` to hide a column. {% tabs %} {% highlight Dart %} @@ -220,9 +218,9 @@ The column can be bound to a property in a data object using the [GridColumn.col ## Checkbox column -By setting the [showCheckboxColumn](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/showCheckboxColumn.html) property to `true`, you can select or deselect individual rows using checkboxes in each row. The checkbox column will be added as the first column. +By setting the [showCheckboxColumn](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/showCheckboxColumn.html) property to `true`, you can select or deselect individual rows using checkboxes in each row. The checkbox column will be added as the first column in the grid. -The selection is applied to rows only if you set the [SfDataGrid.selectionMode](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/selectionMode.html) property other than `none.` +> **Note:** Row selection is applied only if you set the [SfDataGrid.selectionMode](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/selectionMode.html) property to a value other than `none`. The checkbox state automatically synchronizes with the row selection state. {% tabs %} {% highlight Dart %} @@ -291,7 +289,7 @@ The selection is applied to rows only if you set the [SfDataGrid.selectionMode]( ### Show text in the header cell -Display widgets along with the checkbox in the header cell by adding a widget to the [SfDataGrid.checkboxColumnSettings.label](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridCheckboxColumnSettings/label.html) property. +Display widgets along with the checkbox in the header cell by adding a widget to the [DataGridCheckboxColumnSettings.label](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridCheckboxColumnSettings/label.html) property. This allows you to add custom text or icons above or beside the checkbox in the header. {% tabs %} {% highlight Dart %} @@ -362,9 +360,9 @@ Display widgets along with the checkbox in the header cell by adding a widget to ![flutter datagrid shows text in checkbox column header](images/column-types/flutter-datagrid-shows-text-in-checkbox-column-header.png) -### Disable the checkbox in the header cell +### Hide the checkbox in the header cell -By default, a checkbox is displayed in the header cell. By setting the [SfDataGrid.checkboxColumnSettings.showCheckboxOnHeader](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridCheckboxColumnSettings/showCheckboxOnHeader.html) property to `false`, the checkbox can be hidden in the header cell. +By default, a checkbox is displayed in the header cell. By setting the [DataGridCheckboxColumnSettings.showCheckboxOnHeader](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridCheckboxColumnSettings/showCheckboxOnHeader.html) property to `false`, the checkbox can be hidden from the header cell while keeping checkboxes in data rows. {% tabs %} {% highlight Dart %} @@ -435,7 +433,7 @@ By default, a checkbox is displayed in the header cell. By setting the [SfDataGr ### Change the background color of the checkbox column -The background color of the checkbox column can be customized by using the [SfDataGrid.checkboxColumnSettings.backgroundColor](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridCheckboxColumnSettings/backgroundColor.html) property. +The background color of the entire checkbox column can be customized by using the [DataGridCheckboxColumnSettings.backgroundColor](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridCheckboxColumnSettings/backgroundColor.html) property. This property affects both the header and data rows of the checkbox column. {% tabs %} {% highlight Dart %} @@ -506,7 +504,9 @@ The background color of the checkbox column can be customized by using the [SfDa ### Get checked items -Get the checked items by using the [DataGridController.selectedRows](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/selectedRows.html) property because the selection and checkbox's checked states are the same. +Get the checked items by using the [DataGridController.selectedRows](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/selectedRows.html) property. The checkbox state and row selection state are synchronized, so you can retrieve checked rows through the controller's selection properties. + +> **Note:** Ensure the [DataGridController](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController-class.html) is assigned to the `SfDataGrid.controller` property for programmatic access to selection information. {% tabs %} {% highlight Dart %} @@ -596,7 +596,7 @@ Get the checked items by using the [DataGridController.selectedRows](https://pub ### Change the shape of the checkbox column -By default, the checkbox shows in the DataGrid as a square shape. Change the checkbox shape by setting the required shape in the [SfDataGrid.checkboxShape](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/checkboxShape.html) property. +By default, checkboxes in the DataGrid appear as a square shape. Change the checkbox shape by setting the required [`ShapeBorder`](https://api.flutter.dev/flutter/painting/ShapeBorder-class.html) in the [SfDataGrid.checkboxShape](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/checkboxShape.html) property. You can use built-in shapes like `CircleBorder()`, `RoundedRectangleBorder()`, or create a custom shape. {% tabs %} {% highlight Dart %} @@ -659,11 +659,11 @@ The `SfDataGrid` provides the following callback for checkbox interactions: * [onCheckboxValueChanged](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/onCheckboxValueChanged.html): This callback is triggered when the checkbox is selected or deselected, either by tapping on the checkbox or by selecting or deselecting a row (i.e., when the value of the checkbox changes). -The checkbox callbacks provide the following properties in their arguments: +The [DataGridCheckboxValueChangedDetails](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridCheckboxValueChangedDetails-class.html) object passed to the callback provides the following properties: -* [value](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridCheckboxValueChangedDetails/value.html): Represents the current state of the checkbox. -* [row](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridCheckboxValueChangedDetails/row.html): Refers to the DataGridRow linked to the checkbox in the checkbox column. If the checkbox is part of a column header, the value will be null, indicating that it is not linked to any specific data row. -* [rowType](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridCheckboxValueChangedDetails/rowType.html): Defines the type of row associated with the checkbox. It indicates whether the checkbox value in a data row or header row has been modified. +* [value](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridCheckboxValueChangedDetails/value.html): A boolean representing the current state of the checkbox (`true` if checked, `false` if unchecked). +* [row](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridCheckboxValueChangedDetails/row.html): The [DataGridRow](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridRow-class.html) linked to the checkbox. If the checkbox is part of a column header, this value will be null. +* [rowType](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridCheckboxValueChangedDetails/rowType.html): A [RowType](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/RowType.html) enum value that indicates whether the checkbox is in a data row or header row. {% tabs %} {% highlight Dart %} @@ -722,15 +722,17 @@ The checkbox callbacks provide the following properties in their arguments: ### Limitations -The following are the limitations of GridCheckboxColumn: +The following are the limitations of the checkbox column: + +* The checkbox column does not support sorting or other data operations. +* The checkbox column does not support stacked headers in combination with other columns. +* The checkbox column is excluded from exporting operations (PDF, Excel, etc.). -* The checkbox column does not support data operations such as sorting. -* The checkbox column does not support adding the stacked headers along with other columns. -* The checkbox column will be excluded in exporting operations. +## Column header icons on hover -## Show the column header icons on hover +To display column header icons, such as sort and filter icons, when the mouse hovers over a column header, set the [SfDataGrid.showColumnHeaderIconOnHover](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/showColumnHeaderIconOnHover.html) property to `true`. This feature is available only on web and desktop platforms. -To display column header icons, such as sort and filter icons, when the mouse hovers over a column header, set the [SfDataGrid.showColumnHeaderIconOnHover](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/showColumnHeaderIconOnHover.html) property to true. This feature is available only on web and desktop platforms. +> **Note:** This feature requires the [SfDataGrid.allowSorting](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/allowSorting.html) or [SfDataGrid.allowFiltering](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/allowFiltering.html) properties to be enabled for the icons to appear. {% tabs %} {% highlight Dart %} diff --git a/Flutter/datagrid/columns-resizing.md b/Flutter/datagrid/columns-resizing.md index e30200ab7..5cd934b16 100644 --- a/Flutter/datagrid/columns-resizing.md +++ b/Flutter/datagrid/columns-resizing.md @@ -15,14 +15,17 @@ The [SfDataGrid](https://pub.dev/documentation/syncfusion_flutter_datagrid/lates The column resizing indicator appears based on the platform. In web and desktop platforms, the indicator appears when you hover over the right end of the column and drag it. In mobile platforms, the indicator comes into view when you long-press the corresponding column header. -> **NOTE:** -> Column resizing considers the [GridColumn.minimumWidth](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn/minimumWidth.html) and [GridColumn.maximumWidth](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn/maximumWidth.html) properties. +> **Note:** Column resizing considers the [GridColumn.minimumWidth](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn/minimumWidth.html) and [GridColumn.maximumWidth](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn/maximumWidth.html) properties. These limits are enforced to prevent columns from becoming too small or too large during resizing. + +## Basic Column Resizing + +The following example demonstrates the basic column resizing setup. The `columnWidths` map stores the width of each column. Initially, the `DataGrid` applies its default column sizing behavior, and the column widths are updated when the user manually resizes a column. {% tabs %} {% highlight Dart %} late Map columnWidths = { - 'id': double.nan, + 'id': double.nan, // double.nan means use default width until resized 'name': double.nan, 'designation': double.nan, 'salary': double.nan @@ -99,8 +102,8 @@ The column resizing indicator appears based on the platform. In web and desktop By default, the columns are resized by dragging the right end of the columns. `SfDataGrid` provides two modes to perform column resizing: -* `onResize`: The resizing indicator moves based on the dragging gesture. `onColumnResizeUpdate` callback is called when a column is resized. -* `onResizeEnd`: The resizing indicator moves based on the dragging gesture. `onColumnResizeUpdate` callback is called when you release the pointer. +* `onResize`: The resizing indicator moves based on the dragging gesture. `onColumnResizeUpdate` callback is called continuously as the user drags. Use this mode when you want real-time column width updates. +* `onResizeEnd`: The resizing indicator moves based on the dragging gesture. `onColumnResizeUpdate` callback is called only when you release the pointer. Use this mode for better performance when handling expensive operations like persisting changes. The following example demonstrates how to resize a column by setting the [SfDataGrid.columnResizeMode](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/columnResizeMode.html) property to `onResizeEnd`. @@ -186,9 +189,9 @@ The following example demonstrates how to resize a column by setting the [SfData The following callbacks are called when you perform column resizing: -* [onColumnResizeStart](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/onColumnResizeStart.html): Called when column resizing is started. In mobile platforms, it will be called when the resizing indicator appears after you long-press the corresponding column header. In web and desktop platforms, it will be called when you click and drag the right end of the columns. -* `onColumnResizeUpdate`: Called when a column is being resized. Typically, you should set the column width here. -* [onColumnResizeEnd](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/onColumnResizeEnd.html): Called when column resizing is ended. Typically, this will be called when you release the pointer. +* [onColumnResizeStart](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/onColumnResizeStart.html): Called when column resizing is started. In mobile platforms, it will be called when the resizing indicator appears after you long-press the corresponding column header. In web and desktop platforms, it will be called when you click and drag the right end of the columns. Return `true` to allow resizing, or `false` to prevent it. +* `onColumnResizeUpdate`: Called when a column is being resized. Typically, you should set the column width here. The callback provides `ColumnResizeUpdateDetails` with properties: `column` (the GridColumn being resized) and `width` (the new width). Return `true` to apply the change. +* [onColumnResizeEnd](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/onColumnResizeEnd.html): Called when column resizing is ended. This will be called when you release the pointer. The callback provides `ColumnResizeEndDetails` with the final column and width information. {% tabs %} {% highlight Dart %} @@ -273,7 +276,7 @@ The following callbacks are called when you perform column resizing: ## Disable resizing for a particular column -To disable resizing for a particular column, use the `SfDataGrid.onColumnResizeStart` callback and return `false` to the corresponding column. Return `true` for all other columns. +To disable resizing for a particular column, return `false` in the `onColumnResizeStart` callback for that column. Return `true` for all other columns to allow resizing. {% tabs %} {% highlight Dart %} @@ -359,7 +362,7 @@ To disable resizing for a particular column, use the `SfDataGrid.onColumnResizeS ## Disable resizing for the checkbox column -The checkbox column is always added as the first column (index 0). To disable resizing for the checkbox column, use the `SfDataGrid.onColumnResizeStart` callback and return false when the [ColumnResizeStartDetails.columnIndex](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/ColumnResizeStartDetails/columnIndex.html) is 0. +When checkbox selection is enabled (`showCheckboxColumn: true`), the checkbox column is always added as the first column (index 0). To disable resizing for the checkbox column, return `false` in the `onColumnResizeStart` callback when the [ColumnResizeStartDetails.columnIndex](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/ColumnResizeStartDetails/columnIndex.html) is `0`. {% tabs %} {% highlight Dart %} @@ -529,7 +532,9 @@ To prevent a column from being hidden while resizing, use the `GridColumn.minimu The column resizing indicator color and its width can be customized by using the [SfDataGridThemeData.columnResizeIndicatorColor](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/columnResizeIndicatorColor.html) and [SfDataGridThemeData.columnResizeIndicatorStrokeWidth](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/columnResizeIndicatorStrokeWidth.html) properties. -The `SfDataGridThemeData` and `SfDataGridTheme` classes are available in the [syncfusion_flutter_core](https://pub.dev/packages/syncfusion_flutter_core) package. So, import the following file: +> **Note:** The `SfDataGridThemeData` and `SfDataGridTheme` classes are available in the [syncfusion_flutter_core](https://pub.dev/packages/syncfusion_flutter_core) package. Ensure this package is added to your project dependencies. + +Import the following file: {% tabs %} {% highlight Dart %} diff --git a/Flutter/datagrid/columns-sizing.md b/Flutter/datagrid/columns-sizing.md index 771a7a8f6..a34b31cb5 100644 --- a/Flutter/datagrid/columns-sizing.md +++ b/Flutter/datagrid/columns-sizing.md @@ -13,20 +13,32 @@ documentation: ug | Mode | Description | |---------------------------|-----------------------------------------------------| -| ColumnWidthMode.auto | Calculates the width of column based on [GridColumn.columName](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn/columnName.html) and [DataGridCell.value](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridCell/value.html) properties. So, the header and cell contents are not truncated. | +| ColumnWidthMode.auto | Calculates the width of column based on [GridColumn.columnName](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn/columnName.html) and [DataGridCell.value](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridCell/value.html) properties. So, the header and cell contents are not truncated. | | ColumnWidthMode.fitByCellValue | Calculates the width of column based on `DataGridCell.value` property. So, the cell contents are not truncated. | | ColumnWidthMode.fitByColumnName | Calculates the width of column based on `GridColumn.columName` property. So, the header contents are not truncated. | | ColumnWidthMode.lastColumnFill | Applies default Column width to all the columns except last column which is visible and the remaining width from total width of SfDataGrid is set to last column. | | ColumnWidthMode.fill | Divides the total width equally for columns. | -| ColumnWidthMode.none | No sizing. Default column width or defined width set to column. | +| ColumnWidthMode.none | No sizing. Default column width (80.0) or explicitly defined width is set to the column. | -> **NOTE** - [ColumnWidthMode](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/ColumnWidthMode.html) will not work when the column width defined explicitly. `columnWidthMode` calculates column width based on miniumWidth and maximumWidth properties. +> **Note:** [ColumnWidthMode](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/ColumnWidthMode.html) will not work when the column width is defined explicitly. `columnWidthMode` calculates column width based on `minimumWidth` and `maximumWidth` properties. For optimal performance with large datasets, consider using `ColumnWidthMode.none` or `ColumnWidthMode.fill` instead of `ColumnWidthMode.auto`. The following example shows how to set the width equally for columns based on the viewport size. {% tabs %} -{% highlight Dart %} +{% highlight Dart %} + +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; + + List _employees = []; + late EmployeeDataSource _employeeDataSource; + + @override + void initState() { + super.initState(); + _employees = getEmployeeData(); + _employeeDataSource = EmployeeDataSource(employeeData: _employees); + } @override Widget build(BuildContext context) { @@ -68,7 +80,7 @@ The following example shows how to set the width equally for columns based on th padding: EdgeInsets.symmetric(horizontal: 16.0), alignment: Alignment.centerLeft, child: Text( - 'city', + 'City', overflow: TextOverflow.ellipsis, ))), GridColumn( @@ -86,62 +98,73 @@ The following example shows how to set the width equally for columns based on th {% endhighlight %} {% endtabs %} -> **NOTE** -The `GridColumn.columnWidthMode` takes higher priority than the `SfDataGrid.columnWidthMode`. +> **Note:** The `GridColumn.columnWidthMode` takes higher priority than the `SfDataGrid.columnWidthMode`. ![columns filled based on view port size in flutter datagrid](images/autofit-columns/flutter-datagrid-fill-columns.png) ## Consider all the rows to calculate the autofit size -By default, the autofit calculation is performed for only visible rows. You can use the [SfDataGrid.columnWidthCalculationRange](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/columnWidthCalculationRange.html) property as [ColumnWidthCalculationRange.allRows](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/ColumnWidthCalculationRange.html) to perform the autofit calculation for all the available rows. +By default, the autofit calculation is performed for only visible rows. You can use the [SfDataGrid.columnWidthCalculationRange](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/columnWidthCalculationRange.html) property as [ColumnWidthCalculationRange.allRows](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/ColumnWidthCalculationRange.html#allRows) to perform the autofit calculation for all the available rows. {% tabs %} -{% highlight Dart %} +{% highlight Dart %} + +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; + + List _employees = []; + late EmployeeDataSource _employeeDataSource; + + @override + void initState() { + super.initState(); + _employees = getEmployeeData(); + _employeeDataSource = EmployeeDataSource(employeeData: _employees); + } @override Widget build(BuildContext context) { - return SfDataGrid( + return Scaffold( + body: SfDataGrid( source: _employeeDataSource, columnWidthMode: ColumnWidthMode.auto, columnWidthCalculationRange: ColumnWidthCalculationRange.allRows, columns: [ GridColumn( - columnName: 'ID', - label: Container( - padding: EdgeInsets.all(16.0), - alignment: Alignment.centerRight, - child: Text( - 'ID', - softWrap: false, - ))), + columnName: 'id', + label: Container( + padding: EdgeInsets.all(16.0), + alignment: Alignment.centerRight, + child: Text('ID', softWrap: false), + ), + ), GridColumn( - columnName: 'Name', - label: Container( - padding: EdgeInsets.all(16.0), - alignment: Alignment.centerLeft, - child: Text( - 'Name', - softWrap: false, - ))), + columnName: 'name', + label: Container( + padding: EdgeInsets.all(16.0), + alignment: Alignment.centerLeft, + child: Text('Name', softWrap: false), + ), + ), GridColumn( - columnName: 'Designation', - label: Container( - padding: EdgeInsets.all(16.0), - alignment: Alignment.centerLeft, - child: Text( - 'Designation', - softWrap: false, - ))), + columnName: 'designation', + label: Container( + padding: EdgeInsets.all(16.0), + alignment: Alignment.centerLeft, + child: Text('Designation', softWrap: false), + ), + ), GridColumn( - columnName: 'Salary', - label: Container( - padding: EdgeInsets.all(16.0), - alignment: Alignment.centerRight, - child: Text( - 'Salary', - softWrap: false, - ))) - ]); + columnName: 'salary', + label: Container( + padding: EdgeInsets.all(16.0), + alignment: Alignment.centerRight, + child: Text('Salary', softWrap: false), + ), + ), + ], + ), + ); } {% endhighlight %} @@ -149,72 +172,83 @@ By default, the autofit calculation is performed for only visible rows. You can ## Change the padding value for autofit calculation -By default, the EdgeInsets.all(16.0) is added with the auto width or height value. You can change the padding for specific columns by using the [GridColumn.autoFitPadding](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn/autoFitPadding.html) property. +By default, `EdgeInsets.all(16.0)` is added with the auto width or height value. You can change the padding for specific columns by using the [GridColumn.autoFitPadding](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn/autoFitPadding.html) property. You can also use asymmetric padding values (e.g., `EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0)`) for fine-grained control. ->**NOTE** -`GridColumn.autoFitPadding` is applicable for header cell also. +> **Note:** `GridColumn.autoFitPadding` is applicable for header cells as well. {% tabs %} -{% highlight Dart %} +{% highlight Dart %} + +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; + + List _employees = []; + late EmployeeDataSource _employeeDataSource; + + @override + void initState() { + super.initState(); + _employees = getEmployeeData(); + _employeeDataSource = EmployeeDataSource(employees: _employees); + } @override Widget build(BuildContext context) { - return SfDataGrid( + return Scaffold( + body: SfDataGrid( source: _employeeDataSource, columnWidthMode: ColumnWidthMode.auto, columns: [ GridColumn( - columnName: 'id', - autoFitPadding: EdgeInsets.all(10.0), - label: Container( - padding: EdgeInsets.all(10.0), - alignment: Alignment.centerRight, - child: Text( - 'ID', - softWrap: false, - ))), + columnName: 'id', + autoFitPadding: EdgeInsets.all(10.0), + label: Container( + padding: EdgeInsets.all(10.0), + alignment: Alignment.centerRight, + child: Text('ID', softWrap: false), + ), + ), GridColumn( - columnName: 'name', - autoFitPadding: EdgeInsets.all(10.0), - label: Container( - padding: EdgeInsets.all(10.0), - alignment: Alignment.centerLeft, - child: Text( - 'Name', - softWrap: false, - ))), + columnName: 'name', + autoFitPadding: EdgeInsets.all(10.0), + label: Container( + padding: EdgeInsets.all(10.0), + alignment: Alignment.centerLeft, + child: Text('Name', softWrap: false), + ), + ), GridColumn( - columnName: 'designation', - autoFitPadding: EdgeInsets.all(10.0), - label: Container( - padding: EdgeInsets.all(10.0), - alignment: Alignment.centerLeft, - child: Text( - 'Designation', - softWrap: false, - ))), + columnName: 'designation', + autoFitPadding: EdgeInsets.all(10.0), + label: Container( + padding: EdgeInsets.all(10.0), + alignment: Alignment.centerLeft, + child: Text('Designation', softWrap: false), + ), + ), GridColumn( - columnName: 'salary', - autoFitPadding: EdgeInsets.all(10.0), - label: Container( - padding: EdgeInsets.all(10.0), - alignment: Alignment.centerRight, - child: Text( - 'Salary', - softWrap: false, - ))) - ]); + columnName: 'salary', + autoFitPadding: EdgeInsets.all(10.0), + label: Container( + padding: EdgeInsets.all(10.0), + alignment: Alignment.centerRight, + child: Text('Salary', softWrap: false), + ), + ), + ], + ), + ); } class EmployeeDataSource extends DataGridSource { EmployeeDataSource({required List employees}) { _employeeData = employees .map((e) => DataGridRow(cells: [ - DataGridCell(columnName: 'ID', value: e.id), - DataGridCell(columnName: 'Name', value: e.name), + DataGridCell(columnName: 'id', value: e.id), + DataGridCell(columnName: 'name', value: e.name), DataGridCell( - columnName: 'Designation', value: e.designation), - DataGridCell(columnName: 'Salary', value: e.salary), + columnName: 'designation', value: e.designation), + DataGridCell(columnName: 'salary', value: e.salary), ])) .toList(); } @@ -245,71 +279,96 @@ class EmployeeDataSource extends DataGridSource { ## Autofit calculation based on different TextStyle -By default, the cell width is calculated based on the default text style. To calculate the cell width based on different [TextStyle](https://api.flutter.dev/flutter/painting/TextStyle-class.html), just override the [computeHeaderCellWidth](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/ColumnSizer/computeHeaderCellWidth.html) method for the header and [computeCellWidth](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/ColumnSizer/computeCellWidth.html) method for the cell and return the super method with the required `TextStyle.` +By default, the cell width is calculated based on the default text style. To calculate the cell width based on different [TextStyle](https://api.flutter.dev/flutter/painting/TextStyle-class.html), override the [computeHeaderCellWidth](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/ColumnSizer/computeHeaderCellWidth.html) method for the header and [computeCellWidth](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/ColumnSizer/computeCellWidth.html) method for the cell, and return the super method with the required `TextStyle`. {% tabs %} -{% highlight Dart %} +{% highlight Dart %} + +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; + List _employees = []; + late EmployeeDataSource _employeeDataSource; final CustomColumnSizer _customColumnSizer = CustomColumnSizer(); + @override + void initState() { + super.initState(); + _employees = getEmployeeData(); + _employeeDataSource = EmployeeDataSource(employees: _employees); + } + @override Widget build(BuildContext context) { - return SfDataGrid( + return Scaffold( + body: SfDataGrid( source: _employeeDataSource, columnSizer: _customColumnSizer, columnWidthMode: ColumnWidthMode.auto, columns: [ GridColumn( - columnName: 'ID', - autoFitPadding: EdgeInsets.all(12.0), - label: Container( - padding: EdgeInsets.all(12.0), - alignment: Alignment.center, - child: Text( - 'ID', - ))), + columnName: 'id', + autoFitPadding: EdgeInsets.all(12.0), + label: Container( + padding: EdgeInsets.all(12.0), + alignment: Alignment.center, + child: Text('ID'), + ), + ), GridColumn( - columnName: 'Name', - autoFitPadding: EdgeInsets.all(12.0), - label: Container( - padding: EdgeInsets.all(12.0), - alignment: Alignment.center, - child: Text( - 'Name', - style: TextStyle( - fontWeight: FontWeight.bold, fontStyle: FontStyle.italic), - ))), + columnName: 'name', + autoFitPadding: EdgeInsets.all(12.0), + label: Container( + padding: EdgeInsets.all(12.0), + alignment: Alignment.center, + child: Text( + 'Name', + style: TextStyle( + fontWeight: FontWeight.bold, + fontStyle: FontStyle.italic, + ), + ), + ), + ), GridColumn( - columnName: 'Designation', - autoFitPadding: EdgeInsets.all(12.0), - label: Container( - padding: EdgeInsets.all(12.0), - alignment: Alignment.center, - child: Text( - 'Designation', - overflow: TextOverflow.ellipsis, - style: TextStyle( - fontWeight: FontWeight.bold, fontStyle: FontStyle.italic), - ))), + columnName: 'designation', + autoFitPadding: EdgeInsets.all(12.0), + label: Container( + padding: EdgeInsets.all(12.0), + alignment: Alignment.center, + child: Text( + 'Designation', + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontWeight: FontWeight.bold, + fontStyle: FontStyle.italic, + ), + ), + ), + ), GridColumn( - columnName: 'Salary', - autoFitPadding: EdgeInsets.all(12.0), - label: Container( - padding: EdgeInsets.all(12.0), - alignment: Alignment.center, - child: Text('Salary'))), - ]); + columnName: 'salary', + autoFitPadding: EdgeInsets.all(12.0), + label: Container( + padding: EdgeInsets.all(12.0), + alignment: Alignment.center, + child: Text('Salary'), + ), + ), + ], + ), + ); } class EmployeeDataSource extends DataGridSource { EmployeeDataSource({required List employees}) { _employeeData = employees .map((e) => DataGridRow(cells: [ - DataGridCell(columnName: 'ID', value: e.id), - DataGridCell(columnName: 'Name', value: e.name), + DataGridCell(columnName: 'id', value: e.id), + DataGridCell(columnName: 'name', value: e.name), DataGridCell( - columnName: 'Designation', value: e.designation), - DataGridCell(columnName: 'Salary', value: e.salary), + columnName: 'designation', value: e.designation), + DataGridCell(columnName: 'salary', value: e.salary), ])) .toList(); } @@ -327,7 +386,7 @@ class EmployeeDataSource extends DataGridSource { alignment: Alignment.center, padding: EdgeInsets.all(12.0), child: Text(e.value.toString(), - style: (e.columnName == 'Name' || e.columnName == 'Designation') + style: (e.columnName == 'name' || e.columnName == 'designation') ? TextStyle( fontWeight: FontWeight.bold, fontStyle: FontStyle.italic) : null)); @@ -338,7 +397,7 @@ class EmployeeDataSource extends DataGridSource { class CustomColumnSizer extends ColumnSizer { @override double computeHeaderCellWidth(GridColumn column, TextStyle style) { - if (column.columnName == 'Name' || column.columnName == 'Designation') { + if (column.columnName == 'name' || column.columnName == 'designation') { style = TextStyle(fontWeight: FontWeight.bold, fontStyle: FontStyle.italic); } @@ -348,7 +407,7 @@ class CustomColumnSizer extends ColumnSizer { @override double computeCellWidth(GridColumn column, DataGridRow row, Object? cellValue, TextStyle textStyle) { - if (column.columnName == 'Name' || column.columnName == 'Designation') { + if (column.columnName == 'name' || column.columnName == 'designation') { textStyle = TextStyle(fontWeight: FontWeight.bold, fontStyle: FontStyle.italic); } @@ -357,78 +416,94 @@ class CustomColumnSizer extends ColumnSizer { } {% endhighlight %} -{% endtabs %} - -**NOTE** - Download the demo application from [GitHub](https://github.com/SyncfusionExamples/how-to-fit-the-column-based-on-the-different-text-style-in-Flutter-DataTable-sfdatagrid). +{% endtabs %} ![flutter datagrid shows autofit the columns based on different text style](images/autofit-columns/flutter-datagrid-textstyle-customization.png) ## Autofit calculation based on the formatted value -The cell width is calculated by default based on the `DataGridCell.value` property. To autofit the cell width based on the displayed formatted value (This is, DateFormat and NumberFormat), simply override the `computeCellWidth` method and return the super method with the required `cellValue.` +The cell width is calculated by default based on the `DataGridCell.value` property. To autofit the cell width based on the displayed formatted value (that is, DateFormat and NumberFormat), override the `computeCellWidth` method and return the super method with the required `cellValue`. {% tabs %} {% highlight Dart %} +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; import 'package:intl/intl.dart'; + List _employees = []; + late EmployeeDataSource _employeeDataSource; final CustomColumnSizer _customColumnSizer = CustomColumnSizer(); + @override + void initState() { + super.initState(); + _employees = getEmployeeData(); + _employeeDataSource = EmployeeDataSource(employees: _employees); + } + @override Widget build(BuildContext context) { - return SfDataGrid( + return Scaffold( + body: SfDataGrid( source: _employeeDataSource, columnSizer: _customColumnSizer, columnWidthMode: ColumnWidthMode.fitByCellValue, columns: [ GridColumn( - columnName: 'ID', - label: Container( - padding: EdgeInsets.all(16.0), - alignment: Alignment.centerRight, - child: Text( - 'ID', - softWrap: false, - ))), + columnName: 'id', + label: Container( + padding: EdgeInsets.all(16.0), + alignment: Alignment.centerRight, + child: Text('ID', softWrap: false), + ), + ), GridColumn( - columnName: 'Name', - label: Container( - padding: EdgeInsets.all(16.0), - alignment: Alignment.centerLeft, - child: Text( - 'Name', - softWrap: false, - ))), + columnName: 'name', + label: Container( + padding: EdgeInsets.all(16.0), + alignment: Alignment.centerLeft, + child: Text('Name', softWrap: false), + ), + ), GridColumn( - columnName: 'DOB', - label: Container( - padding: EdgeInsets.all(16.0), - alignment: Alignment.centerLeft, - child: Text( - 'DOB', - softWrap: false, - ))), + columnName: 'dob', + label: Container( + padding: EdgeInsets.all(16.0), + alignment: Alignment.centerLeft, + child: Text('DOB', softWrap: false), + ), + ), GridColumn( - columnName: 'Salary', - label: Container( - padding: EdgeInsets.all(16.0), - alignment: Alignment.centerRight, - child: Text( - 'Salary', - softWrap: false, - ))) - ]); + columnName: 'salary', + label: Container( + padding: EdgeInsets.all(16.0), + alignment: Alignment.centerRight, + child: Text('Salary', softWrap: false), + ), + ), + ], + ), + ); } +class Employee { + Employee(this.id, this.name, this.dob, this.salary); + + final int id; + final String name; + final DateTime dob; + final int salary; +} + class EmployeeDataSource extends DataGridSource { EmployeeDataSource({required List employees}) { _employeeData = employees .map((e) => DataGridRow(cells: [ - DataGridCell(columnName: 'ID', value: e.id), - DataGridCell(columnName: 'Name', value: e.name), - DataGridCell(columnName: 'DOB', value: e.dob), - DataGridCell(columnName: 'Salary', value: e.salary), + DataGridCell(columnName: 'id', value: e.id), + DataGridCell(columnName: 'name', value: e.name), + DataGridCell(columnName: 'dob', value: e.dob), + DataGridCell(columnName: 'salary', value: e.salary), ])) .toList(); } @@ -443,9 +518,9 @@ class EmployeeDataSource extends DataGridSource { return DataGridRowAdapter( cells: row.getCells().map((e) { late String cellValue; - if (e.columnName == 'DOB') { + if (e.columnName == 'dob') { cellValue = DateFormat.yMMMMd('en_US').format(e.value); - } else if (e.columnName == 'Salary') { + } else if (e.columnName == 'salary') { cellValue = NumberFormat.simpleCurrency(decimalDigits: 0).format(e.value); } else { @@ -465,9 +540,9 @@ class CustomColumnSizer extends ColumnSizer { @override double computeCellWidth(GridColumn column, DataGridRow row, Object? cellValue, TextStyle textStyle) { - if (column.columnName == 'DOB') { + if (column.columnName == 'dob') { cellValue = DateFormat.yMMMMd('en_US').format(cellValue as DateTime); - } else if (column.columnName == 'Salary') { + } else if (column.columnName == 'salary') { cellValue = NumberFormat.simpleCurrency(decimalDigits: 0).format(cellValue); } @@ -477,64 +552,72 @@ class CustomColumnSizer extends ColumnSizer { } {% endhighlight %} -{% endtabs %} - -**NOTE** - Download the demo application from [GitHub](https://github.com/SyncfusionExamples/how-to-fit-the-columns-based-on-the-formatted-value-in-Flutter-datatable-sfdatagrid). +{% endtabs %} ![flutter datagrid shows autofit the columns based on formatted cell value](images/autofit-columns/flutter-datagrid-formatted-cellvalue.png) ## Fill the remaining width for any column -While setting `SfDataGrid.columnWidthMode` as `lastColumnFill` the remaining width is applied to the last column. The remaining width of a specific column can be applied by setting the `GridColumn.columnWidthMode` property. +While setting `SfDataGrid.columnWidthMode` as `lastColumnFill`, the remaining width is applied to the last column. The remaining width of a specific column can be applied by setting the `GridColumn.columnWidthMode` property. {% tabs %} -{% highlight Dart %} +{% highlight Dart %} + +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; + + List _employees = []; + late EmployeeDataSource _employeeDataSource; + + @override + void initState() { + super.initState(); + _employees = getEmployeeData(); + _employeeDataSource = EmployeeDataSource(employeeData: _employees); + } @override Widget build(BuildContext context) { return Scaffold( - body: SfDataGrid( - source: _employeeDataSource, - columnWidthMode: ColumnWidthMode.lastColumnFill, - columns: [ + body: SfDataGrid( + source: _employeeDataSource, + columnWidthMode: ColumnWidthMode.lastColumnFill, + columns: [ GridColumn( - columnName: 'id', - label: Container( - padding: EdgeInsets.symmetric(horizontal: 16.0), - alignment: Alignment.centerRight, - child: Text( - 'ID', - overflow: TextOverflow.ellipsis, - ))), + 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, - ))), + columnName: 'name', + label: Container( + padding: EdgeInsets.symmetric(horizontal: 16.0), + alignment: Alignment.centerLeft, + child: Text('Name', overflow: TextOverflow.ellipsis), + ), + ), GridColumn( - columnName: 'salary', - label: Container( - padding: EdgeInsets.symmetric(horizontal: 16.0), - alignment: Alignment.centerRight, - child: Text( - 'Salary', - overflow: TextOverflow.ellipsis, - ))), + columnName: 'salary', + label: Container( + padding: EdgeInsets.symmetric(horizontal: 16.0), + alignment: Alignment.centerRight, + child: Text('Salary', overflow: TextOverflow.ellipsis), + ), + ), GridColumn( - columnName: 'designation', - label: Container( - padding: EdgeInsets.symmetric(horizontal: 16.0), - alignment: Alignment.centerLeft, - child: Text( - 'Designation', - overflow: TextOverflow.ellipsis, - ))) - ])); + columnName: 'designation', + label: Container( + padding: EdgeInsets.symmetric(horizontal: 16.0), + alignment: Alignment.centerLeft, + child: Text('Designation', overflow: TextOverflow.ellipsis), + ), + ), + ], + ), + ); } {% endhighlight %} @@ -542,55 +625,66 @@ While setting `SfDataGrid.columnWidthMode` as `lastColumnFill` the remaining wi ![The last column is filled in view in flutter datagrid](images/autofit-columns/flutter-datagrid-fill-lastcolumn.png) -The below example shows Name column is set as `lastColumnFill` mode. +The following example shows Name column is set as `lastColumnFill` mode. {% tabs %} -{% highlight Dart %} - +{% highlight Dart %} + +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; + + List _employees = []; + late EmployeeDataSource _employeeDataSource; + + @override + void initState() { + super.initState(); + _employees = getEmployeeData(); + _employeeDataSource = EmployeeDataSource(employeeData: _employees); + } + @override Widget build(BuildContext context) { return Scaffold( - body: SfDataGrid( - source: _employeeDataSource, - columns: [ + 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, - ))), + columnName: 'id', + label: Container( + padding: EdgeInsets.symmetric(horizontal: 16.0), + alignment: Alignment.centerRight, + child: Text('ID', overflow: TextOverflow.ellipsis), + ), + ), GridColumn( - columnName: 'name', - columnWidthMode: ColumnWidthMode.lastColumnFill, - label: Container( - padding: EdgeInsets.symmetric(horizontal: 16.0), - alignment: Alignment.centerLeft, - child: Text( - 'Name', - overflow: TextOverflow.ellipsis, - ))), + columnName: 'name', + columnWidthMode: ColumnWidthMode.lastColumnFill, + label: Container( + padding: EdgeInsets.symmetric(horizontal: 16.0), + alignment: Alignment.centerLeft, + child: Text('Name', overflow: TextOverflow.ellipsis), + ), + ), GridColumn( - columnName: 'salary', - label: Container( - padding: EdgeInsets.symmetric(horizontal: 16.0), - alignment: Alignment.centerRight, - child: Text( - 'Salary', - overflow: TextOverflow.ellipsis, - ))), + columnName: 'salary', + label: Container( + padding: EdgeInsets.symmetric(horizontal: 16.0), + alignment: Alignment.centerRight, + child: Text('Salary', overflow: TextOverflow.ellipsis), + ), + ), GridColumn( - columnName: 'designation', - label: Container( - padding: EdgeInsets.symmetric(horizontal: 16.0), - alignment: Alignment.centerLeft, - child: Text( - 'Designation', - overflow: TextOverflow.ellipsis, - ))) - ])); + columnName: 'designation', + label: Container( + padding: EdgeInsets.symmetric(horizontal: 16.0), + alignment: Alignment.centerLeft, + child: Text('Designation', overflow: TextOverflow.ellipsis), + ), + ), + ], + ), + ); } {% endhighlight %} @@ -600,12 +694,12 @@ The below example shows Name column is set as `lastColumnFill` mode. ## Recalculating column widths when datasource is changed -By default, column widths are calculated based on the `columnWidthMode` property on the initial loading of the Datagrid. When the data source is changed for the same datagrid at run time, the Datagrid does not recalculate the column widths. To recalculate the column widths at run time when the data source is changed or data is updated, override the [shouldRecalculateColumnWidths](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/shouldRecalculateColumnWidths.html) method and return `true.` - -Returning true may impact performance as the column widths are recalculated again (whenever the notifyListeners is called). If you know that column widths will be the same whenever underlying data changes, return `false` from this method. +By default, column widths are calculated based on the `columnWidthMode` property on the initial loading of the DataGrid. When the data source is changed for the same DataGrid at run time, the DataGrid does not recalculate the column widths. To recalculate the column widths at run time when the data source is changed or data is updated, override the [shouldRecalculateColumnWidths](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/shouldRecalculateColumnWidths.html) method and return `true`. Then, call `notifyListeners()` to trigger the recalculation. + +> **Note:** Returning `true` may impact performance as the column widths are recalculated whenever `notifyListeners()` is called. If you know that column widths will be the same whenever underlying data changes, return `false` from this method. {% tabs %} -{% highlight Dart %} +{% highlight Dart %} class EmployeeDataSource extends DataGridSource { EmployeeDataSource({required List employees}) { @@ -647,7 +741,21 @@ class EmployeeDataSource extends DataGridSource { bool shouldRecalculateColumnWidths() { return true; } -} + // Call this method when data is updated to recalculate column widths + void updateData(List employees) { + dataGridRows = employees + .map((dataGridRow) => DataGridRow(cells: [ + DataGridCell(columnName: 'id', value: dataGridRow.id), + DataGridCell(columnName: 'name', value: dataGridRow.name), + DataGridCell( + columnName: 'designation', value: dataGridRow.designation), + DataGridCell( + columnName: 'salary', value: dataGridRow.salary), + ])) + .toList(); + notifyListeners(); + } +} {% endhighlight %} {% endtabs %} diff --git a/Flutter/datagrid/conditional-styling.md b/Flutter/datagrid/conditional-styling.md index 26a0408a0..18498273d 100644 --- a/Flutter/datagrid/conditional-styling.md +++ b/Flutter/datagrid/conditional-styling.md @@ -1,7 +1,7 @@ --- layout: post -title: Conditional Styling in Flutter DataGrid | DataTable | Syncfusion -description: Learn here all about how to style the rows and columns in Syncfusion Flutter DataGrid (SfDataGrid) widget and more. +title: Conditional Styling in Flutter DataGrid | SfDataGrid | Syncfusion +description: Learn here all about how to style the rows and cells in Syncfusion Flutter DataGrid (SfDataGrid) widget and more. platform: flutter control: SfDataGrid documentation: ug @@ -11,11 +11,36 @@ documentation: ug The [SfDataGrid](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid-class.html) allows customizing the style of individual cells and rows based on your requirements. You can customize your widget in the `DataGridSource.buildRow` method with the help of `DataGridRowAdapter`. +## Employee Model Class + +The following examples use an `Employee` model class. Define it as shown below: + +```dart +class Employee { + Employee({ + required this.id, + required this.name, + required this.designation, + required this.salary, + }); + + final int id; + final String name; + final String designation; + final int salary; +} +``` + +## When to Use Cell-Level vs Row-Level Styling + +- **Cell-level styling:** Use when you need to style specific cells based on their individual content or column type. This allows fine-grained control over individual cell appearance. +- **Row-level styling:** Use when you want to apply consistent styling across an entire row based on row data. This is more efficient for styling multiple cells at once. + ## Cells ### Styling based on content -The appearance of cells in `SfDataGrid` can be customized conditionally based on their content by setting your widget to the `DataGridRowAdapter.cells`. +Customize the appearance of cells conditionally based on their content by defining custom widgets in the `DataGridRowAdapter.cells` property. In the example below, cells in the designation column are styled with different background colors and text styles based on their values. {% tabs %} {% highlight Dart %} @@ -148,7 +173,7 @@ class EmployeeDataSource extends DataGridSource { ### Styling alternate cells -The appearance of alternating cells in a column can be customized conditionally by using the `DataGridSource.buildRow` method. +Customize the appearance of alternating cells in a column by using the `DataGridSource.buildRow` method and the `effectiveRows` property to determine the row index. The `effectiveRows` property contains the sorted collection of rows if sorting is applied. {% tabs %} {% highlight Dart %} @@ -215,7 +240,7 @@ class EmployeeDataSource extends DataGridSource { ### Styling based on content -The appearance of rows in `SfDataGrid` can be customized conditionally based on the content using `DataGridRowAdapter.color`. +Customize the appearance of rows conditionally based on their content using the `DataGridRowAdapter.color` property. In the example below, rows are styled with different background and text colors based on salary values. {% tabs %} {% highlight Dart %} @@ -290,7 +315,7 @@ class EmployeeDataSource extends DataGridSource { ### Styling alternate rows -The appearance of the alternating rows in `SfDataGrid` can be customized using the `DataGridRowAdapter.color`. Use the [effectiveRows](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/effectiveRows.html) property to get the index of the row. This collection contains the sorted collection if the sorting is applied. +Customize the appearance of alternating rows in `SfDataGrid` using the `DataGridRowAdapter.color` property. Use the [effectiveRows](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/effectiveRows.html) property to get the row index. The `effectiveRows` collection contains sorted rows when sorting is applied, ensuring alternate row styling works correctly with sorted data. {% tabs %} {% highlight Dart %} diff --git a/Flutter/datagrid/data-binding.md b/Flutter/datagrid/data-binding.md index 0de91d2b5..2ea9d6a25 100644 --- a/Flutter/datagrid/data-binding.md +++ b/Flutter/datagrid/data-binding.md @@ -1,7 +1,7 @@ --- layout: post title: Data Binding in Flutter DataGrid | DataTable | Syncfusion -description: Learn how to set the Data source for Syncfusion Flutter DataGrid (SfDataGrid) widget and more. +description: Learn how to configure and manage the data source for Syncfusion Flutter DataGrid (SfDataGrid) to display data efficiently. platform: flutter control: SfDataGrid documentation: ug @@ -15,15 +15,28 @@ The [SfDataGrid](https://pub.dev/documentation/syncfusion_flutter_datagrid/lates * [rows](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/rows.html) - The number of rows in a Datagrid and row selection depends on the `rows.` Set the `DataGridRow` collection required for Datagrid in `rows`. -* [buildRow](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/buildRow.html) - The widget needed for the cells is obtained from `DataGridRowAdapter`. +* [buildRow](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/buildRow.html) - The widgets for cells are built using `DataGridRowAdapter`. `DataGridSource` objects are expected to be long-lived, not recreated with each build. +> **Note:** Ensure the `columnName` property in `DataGridCell` matches the `columnName` in the corresponding `GridColumn` definitions. This alignment is essential for the DataGrid to correctly display and manage the data. + The following example shows how to create the `DataGridSource`, {% tabs %} {% highlight dart %} +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; +import 'package:flutter/material.dart'; + +class Employee { + Employee(this.id, this.name, this.designation, this.salary); + final int id; + final String name; + final String designation; + final int salary; +} + class EmployeeDataSource extends DataGridSource { EmployeeDataSource({required List employees}) { dataGridRows = employees @@ -69,23 +82,33 @@ The following example shows how to set the `source` property in `SfDataGrid` {% tabs %} {% highlight dart %} - late EmployeeDataSource _employeeDataSource; - List _employees = []; +List getEmployeeData() { + return [ + Employee(1001, 'James', 'Project Manager', 20000), + Employee(1002, 'Kathryn', 'Manager', 30000), + Employee(1003, 'Lara', 'Developer', 15000), + Employee(1004, 'Michael', 'Developer', 15000), + Employee(1005, 'Martin', 'Developer', 15000), + ]; +} - @override - void initState() { - super.initState(); - _employees = getEmployeeData(); - _employeeDataSource = EmployeeDataSource(employees: _employees); - } +late EmployeeDataSource _employeeDataSource; +List _employees = []; + +@override +void initState() { + super.initState(); + _employees = getEmployeeData(); + _employeeDataSource = EmployeeDataSource(employees: _employees); +} @override - Widget build(BuildContext context) { - return Scaffold( - body: SfDataGrid( - source: _employeeDataSource, - columnWidthMode: ColumnWidthMode.lastColumnFill, - columns: [ +Widget build(BuildContext context) { + return Scaffold( + body: SfDataGrid( + source: _employeeDataSource, + columnWidthMode: ColumnWidthMode.lastColumnFill, + columns: [ GridColumn( columnName: 'id', label: Container( @@ -123,86 +146,101 @@ The following example shows how to set the `source` property in `SfDataGrid` overflow: TextOverflow.ellipsis, ))) ])); - } +} {% endhighlight %} {% endtabs %} +> **Note:** `ColumnWidthMode.lastColumnFill` automatically adjusts the width of the last column to fill any remaining space in the DataGrid. + ## Data manipulation in Flutter DataGrid (SfDataGrid) -`SfDataGrid` provides support to update or refresh the DataGrid when underlying data is updated (i.e. CRUD operation is performed in an underlying data). +`SfDataGrid` provides support to update or refresh the DataGrid when underlying data is updated via CRUD operations. -If a row is added, removed, or replaced in an underlying data source, call the [notifyListeners](https://api.flutter.dev/flutter/foundation/ChangeNotifier/notifyListeners.html). +> **Note:** +- `notifyListeners` must be called from inside the `DataGridSource`. Since it is a protected method, wrap it in a public method like `updateDataGridSource` that can be called from the widget level. +- Requires `syncfusion_flutter_datagrid` package version 20.0.0 or later. -In the following example, a row is added, and `notifyListeners` is called in the `onPressed` callback of the `TextButton`. Since `notifyListeners` is a protected method, the `updateDataGridSource` method the `notifyListeners` method. You can call the `updateDataGridSource` methods at the widget level to refresh the Datagrid. +If a row is added, removed, or replaced in an underlying data source, call the [notifyListeners](https://api.flutter.dev/flutter/foundation/ChangeNotifier/notifyListeners.html) method to notify the DataGrid to refresh. -N> `notifyListeners` should be called from inside the `DataGridSource`. +In the following example, a row is added, and `notifyListeners` is called through the `updateDataGridSource` method in the `onPressed` callback of the `TextButton`. {% tabs %} {% highlight Dart %} - - final List _employees = []; - final EmployeeDataSource _employeeDataSource = EmployeeDataSource(); - @override - Widget build(BuildContext context) { - return Scaffold( - body: Column(children: [ - TextButton( - child: const Text('Add row'), - onPressed: () { - _employees.add(Employee(10011, 'Steve', 'Designer', 15000)); - _employeeDataSource.buildDataGridRows(); - _employeeDataSource.updateDataGridSource(); - }), - 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, - ))) - ]) - ])); - } +List getEmployeeData() { + return [ + Employee(1001, 'James', 'Project Manager', 20000), + Employee(1002, 'Kathryn', 'Manager', 30000), + Employee(1003, 'Lara', 'Developer', 15000), + ]; +} -class EmployeeDataSource extends DataGridSource { - EmployeeDataSource() { - buildDataGridRows(); - } +List _employees = []; +final EmployeeDataSource _employeeDataSource = EmployeeDataSource(); - void buildDataGridRows() { - dataGridRows = _employees +@override +void initState() { + super.initState(); + _employees = getEmployeeData(); + _employeeDataSource.buildDataGridRows(_employees); +} + +@override +Widget build(BuildContext context) { + return Scaffold( + body: Column(children: [ + TextButton( + child: const Text('Add row'), + onPressed: () { + _employees.add(Employee(10011, 'Steve', 'Designer', 15000)); + _employeeDataSource.buildDataGridRows(_employees); + _employeeDataSource.updateDataGridSource(); + }), + 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, + ))) + ]) + ])); +} + +class EmployeeDataSource extends DataGridSource { + void buildDataGridRows(List employees) { + dataGridRows = employees .map((dataGridRow) => DataGridRow(cells: [ DataGridCell(columnName: 'id', value: dataGridRow.id), DataGridCell(columnName: 'name', value: dataGridRow.name), @@ -244,87 +282,97 @@ class EmployeeDataSource extends DataGridSource { {% endhighlight %} {% endtabs %} -If the value of a specific cell is updated, you can call the `notifyDataSourceListeners` method with the [RowColumnIndex](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/RowColumnIndex-class.html) argument, which refers to the corresponding row and column index of the cell. -This way, DataGrid refreshes only the corresponding cell alone. +If the value of a specific cell is updated, you can call the `notifyDataSourceListeners` method with the [RowColumnIndex](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/RowColumnIndex-class.html) argument to refresh only that specific cell, improving performance by avoiding unnecessary full DataGrid refreshes. The `RowColumnIndex` takes two parameters: row index and column index (both 0-based). -In the following example, a cell value is updated, and `notifyDataSourceListeners` is called in the `onPressed` callback of the `TextButton.` +In the following example, a cell value is updated, and `notifyDataSourceListeners` is called in the `onPressed` callback of the `TextButton` with `RowColumnIndex(0, 3)` to refresh only the salary cell in the first row. {% tabs %} {% highlight Dart %} - final List _employees = []; - final EmployeeDataSource _employeeDataSource = EmployeeDataSource(); +List getEmployeeData() { + return [ + Employee(1001, 'James', 'Project Manager', 20000), + Employee(1002, 'Kathryn', 'Manager', 30000), + Employee(1003, 'Lara', 'Developer', 15000), + ]; +} - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Syncfusion Flutter DataGrid'), - ), - body: Column(children: [ - TextButton( - child: const Text('Update cell value'), - onPressed: () { - _employees[0].salary = 25000; - _employeeDataSource.dataGridRows[0] = DataGridRow(cells: [ - DataGridCell(value: _employees[0].id, columnName: 'id'), - DataGridCell(value: _employees[0].name, columnName: 'name'), - DataGridCell( - value: _employees[0].designation, - columnName: 'designation'), - DataGridCell(value: _employees[0].salary, columnName: 'salary'), - ]); - _employeeDataSource.updateDataGridSource( - rowColumnIndex: RowColumnIndex(0, 3)); - }), - 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, - ))) - ]) - ])); - } +List _employees = []; +final EmployeeDataSource _employeeDataSource = EmployeeDataSource(); -class EmployeeDataSource extends DataGridSource { - EmployeeDataSource() { - buildDataGridRows(); - } +@override +void initState() { + super.initState(); + _employees = getEmployeeData(); + _employeeDataSource.buildDataGridRows(_employees); +} + +@override +Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Syncfusion Flutter DataGrid'), + ), + body: Column(children: [ + TextButton( + child: const Text('Update cell value'), + onPressed: () { + _employees[0].salary = 25000; + _employeeDataSource.dataGridRows[0] = DataGridRow(cells: [ + DataGridCell(value: _employees[0].id, columnName: 'id'), + DataGridCell(value: _employees[0].name, columnName: 'name'), + DataGridCell( + value: _employees[0].designation, + columnName: 'designation'), + DataGridCell(value: _employees[0].salary, columnName: 'salary'), + ]); + _employeeDataSource.updateDataGridSource( + rowColumnIndex: RowColumnIndex(0, 3)); + }), + 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, + ))) + ]) + ])); +} - void buildDataGridRows() { - dataGridRows = _employees +class EmployeeDataSource extends DataGridSource { + void buildDataGridRows(List employees) { + dataGridRows = employees .map((dataGridRow) => DataGridRow(cells: [ DataGridCell(columnName: 'id', value: dataGridRow.id), DataGridCell(columnName: 'name', value: dataGridRow.name), @@ -358,10 +406,16 @@ class EmployeeDataSource extends DataGridSource { }).toList()); } - void updateDataGridSource({required RowColumnIndex rowColumnIndex}) { - notifyDataSourceListeners(rowColumnIndex: rowColumnIndex); + void updateDataGridSource({RowColumnIndex? rowColumnIndex}) { + if (rowColumnIndex != null) { + notifyDataSourceListeners(rowColumnIndex: rowColumnIndex); + } else { + notifyListeners(); + } } } {% endhighlight %} {% endtabs %} + +> **Note:** Use `notifyDataSourceListeners` with a specific `RowColumnIndex` for better performance when updating individual cells. Use `notifyListeners` only when the entire row or multiple cells need to be refreshed. diff --git a/Flutter/datagrid/editing.md b/Flutter/datagrid/editing.md index 388d1e87c..6e436c2d8 100644 --- a/Flutter/datagrid/editing.md +++ b/Flutter/datagrid/editing.md @@ -20,13 +20,19 @@ The following arguments are passed in the `buildEditWidget` method. * [column](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn-class.html): Gets the Grid Column of the SfDataGrid. * [submitCell](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/CellSubmit.html): Programmatically call to end the editing. Typically, this method can be called when the widget completes its editing. For example, `TextField.onSubmitted` method is called whenever TextField ends its editing. So, you can simply call submitCell method. This will automatically call the DataGridSource. -It is recommended to save the edited value through editors in the [DataGridSource.onCellSubmit](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/onCellSubmit.html) method. The `onCellSubmit` method will be called whenever the [submitCell](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/CellSubmit.html) method from the [buildEditWidget](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/buildEditWidget.html) method is called, or when other cells are navigated while a cell is in edit mode. +We recommend saving the edited value through the editor widgets in the [DataGridSource.onCellSubmit](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/onCellSubmit.html) method. The `onCellSubmit` method will be called whenever the [submitCell](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/CellSubmit.html) method from the [buildEditWidget](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/buildEditWidget.html) method is called, or when other cells are navigated while a cell is in edit mode. The following example shows how to enable editing in Datagrid and commit the edited cell value in the `onCellSubmit` method. +> **Note:** The `firstWhereOrNull` method is from the [collection](https://pub.dev/packages/collection) package. Add it to your `pubspec.yaml` dependencies and import with `import 'package:collection/collection.dart';` + {% tabs %} {% highlight dart %} +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; +import 'package:collection/collection.dart'; + @override Widget build(BuildContext context) { return Scaffold( @@ -41,74 +47,90 @@ The following example shows how to enable editing in Datagrid and commit the edi label: Container( padding: EdgeInsets.symmetric(horizontal: 16.0), alignment: Alignment.centerRight, - child: Text( - 'ID', - overflow: TextOverflow.ellipsis, - ) - ) + 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, - ) - ) + 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, - ) - ) + 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, - ) - ) + child: Text('Salary', overflow: TextOverflow.ellipsis), + ), ), - ] - ) + ], + ), ); } class EmployeeDataSource extends DataGridSource { - /// Helps to hold the new value of all editable widgets. - /// Based on the new value we will commit the new value into the corresponding - /// DataGridCell on the onCellSubmit method. + /// Holds the underlying data for the DataGrid + late List _employees; + + /// Stores the new value of the edited cell dynamic newCellValue; - /// Helps to control the editable text in the [TextField] widget. + /// Controls the editable text in the [TextField] widget TextEditingController editingController = TextEditingController(); + EmployeeDataSource({required List employeeData}) { + _employees = employeeData; + + dataGridRows = _employees.map((Employee employee) { + return DataGridRow( + cells: [ + DataGridCell(columnName: 'id', value: employee.id), + DataGridCell(columnName: 'name', value: employee.name), + DataGridCell( + columnName: 'designation', + value: employee.designation, + ), + DataGridCell(columnName: 'salary', value: employee.salary), + ], + ); + }).toList(); + } + + /// List to store DataGridRow objects + late List dataGridRows; + @override - Future onCellSubmit(DataGridRow dataGridRow, RowColumnIndex rowColumnIndex, - GridColumn column) async { - final dynamic oldValue = dataGridRow - .getCells() - .firstWhereOrNull((DataGridCell dataGridCell) => - dataGridCell.columnName == column.columnName) - ?.value ?? + Future onCellSubmit( + DataGridRow dataGridRow, + RowColumnIndex rowColumnIndex, + GridColumn column, + ) async { + final dynamic oldValue = + dataGridRow + .getCells() + .firstWhereOrNull( + (DataGridCell dataGridCell) => + dataGridCell.columnName == column.columnName, + ) + ?.value ?? ''; final int dataRowIndex = dataGridRows.indexOf(dataGridRow); - + if (newCellValue == null || oldValue == newCellValue) { return; } - + if (column.columnName == 'id') { dataGridRows[dataRowIndex].getCells()[rowColumnIndex.columnIndex] = DataGridCell(columnName: 'id', value: newCellValue); @@ -129,25 +151,50 @@ class EmployeeDataSource extends DataGridSource { } @override - Widget? buildEditWidget(DataGridRow dataGridRow, - RowColumnIndex rowColumnIndex, GridColumn column, CellSubmit submitCell) { + List get rows => dataGridRows; + + @override + DataGridRowAdapter buildRow(DataGridRow row) { + return DataGridRowAdapter( + cells: row.getCells().map((DataGridCell cell) { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + alignment: (cell.columnName == 'id' || cell.columnName == 'salary') + ? Alignment.centerRight + : Alignment.centerLeft, + child: Text(cell.value.toString()), + ); + }).toList(), + ); + } + + @override + Widget? buildEditWidget( + DataGridRow dataGridRow, + RowColumnIndex rowColumnIndex, + GridColumn column, + CellSubmit submitCell, + ) { // Text going to display on editable widget - final String displayText = dataGridRow - .getCells() - .firstWhereOrNull((DataGridCell dataGridCell) => - dataGridCell.columnName == column.columnName) - ?.value - ?.toString() ?? + final String displayText = + dataGridRow + .getCells() + .firstWhereOrNull( + (DataGridCell dataGridCell) => + dataGridCell.columnName == column.columnName, + ) + ?.value + ?.toString() ?? ''; - + // The new cell value must be reset. // To avoid committing the [DataGridCell] value that was previously edited // into the current non-modified [DataGridCell]. newCellValue = null; - + final bool isNumericType = column.columnName == 'id' || column.columnName == 'salary'; - + return Container( padding: const EdgeInsets.all(8.0), alignment: isNumericType ? Alignment.centerRight : Alignment.centerLeft, @@ -186,8 +233,9 @@ class EmployeeDataSource extends DataGridSource { ![flutter datagrid editing](images/editing/datagrid_editing.gif) ->**NOTE** - Download demo application from [GitHub](https://github.com/SyncfusionExamples/how-to-perform-editing-in-flutter-datatable-sfdatagrid). +> **Note:** The `TextEditingController` used in the example should be disposed to free up resources. Consider implementing disposal in your State class: `@override void dispose() { editingController.dispose(); super.dispose(); }` + +> **Reference:** Download demo application from [GitHub](https://github.com/SyncfusionExamples/how-to-perform-editing-in-flutter-datatable-sfdatagrid). ## Disable the editing for the specific column @@ -260,8 +308,16 @@ To disable the editing for a particular column, set the [GridColumn.allowEditing ![flutter datagrid disable the editing for specific column](images/editing/disable_editing.gif) +> **Note:** Download demo application from [GitHub](https://github.com/SyncfusionExamples/how-to-perform-editing-in-flutter-datatable-sfdatagrid). + ## Entering edit mode +The [SfDataGrid.editingGestureType](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/editingGestureType.html) property controls how a cell enters edit mode. The available options are: + +* **doubleTap**: Cell enters edit mode on double-tap (default behavior) +* **tap**: Cell enters edit mode on single tap +* **longPress**: Cell enters edit mode on long press + By default, a cell will enter edit mode when you double-tap it. To enable editing with a single tap, set the [SfDataGrid.editingGestureType](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/editingGestureType.html) property to tap. {% tabs %} @@ -331,9 +387,11 @@ By default, a cell will enter edit mode when you double-tap it. To enable editin ## Methods +> **Note:** The editing life cycle consists of three key methods: `onCellBeginEdit` (called when entering edit mode), `canSubmitCell` (called before exiting edit mode for validation), and `onCellSubmit` (called when changes are confirmed). All methods are asynchronous-capable. + ### onCellBeginEdit -The [DataGridSource.onCellBeginEdit](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/onCellBeginEdit.html) method is called when a cell enters edit mode. Return false if you don’t want specific cells to enter edit mode. The following arguments are passed in this method: +The [DataGridSource.onCellBeginEdit](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/onCellBeginEdit.html) method is called when a cell enters edit mode. This is a synchronous method where you can prevent specific cells from entering edit mode by returning `false`. The following arguments are passed in this method: * [row](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridRow-class.html): Gets the DataGridRow of the SfDataGrid. * [rowColumnIndex](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/RowColumnIndex-class.html): Gets the current row and column index of the DataGrid. @@ -360,7 +418,7 @@ class EmployeeDataSource extends DataGridSource { ### canSubmitCell -The [DataGridSource.canSubmitCell](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/canSubmitCell.html) is called before the cell is ending its editing. If you want to restrict the cell from being end its editing, you can return false. [onCellSubmit](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/onCellSubmit.html) will be called only if the `canSubmitCell` returns true. The following arguments are passed in this method, +The [DataGridSource.canSubmitCell](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/canSubmitCell.html) method is called before the cell exits edit mode. This is an asynchronous method used for validating the edited value. If validation fails, return `false` to retain the cell in edit mode. The [onCellSubmit](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/onCellSubmit.html) method will only be called if `canSubmitCell` returns `true`. The following arguments are passed in this method: * [row](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridRow-class.html): Gets the DataGridRow of the SfDataGrid. * [rowColumnIndex](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/RowColumnIndex-class.html): Gets the current row and column index of the DataGrid. @@ -372,26 +430,31 @@ The [DataGridSource.canSubmitCell](https://pub.dev/documentation/syncfusion_flut class EmployeeDataSource extends DataGridSource { @override Future canSubmitCell(DataGridRow dataGridRow, RowColumnIndex rowColumnIndex, - GridColumn column) { + GridColumn column) async { if (column.columnName == 'id' && newCellValue == null) { - // Return false, to retain in edit mode. - // To avoid null value for cell + // Return false to retain in edit mode and prevent null values return false; - } else { - return true; + } + if (column.columnName == 'salary' && newCellValue is int) { + // Validate salary value is within acceptable range + if (newCellValue < 0 || newCellValue > 1000000) { + return false; // Invalid salary, retain edit mode + } } + return true; } } {% endhighlight %} {% endtabs %} +> **Note:** To display validation error messages to users, consider showing an error message dialog in the `canSubmitCell` method when returning `false`, or use a validation field overlay on the edit widget in `buildEditWidget`. + ### onCellSubmit -The [DataGridSource.onCellSubmit](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/onCellSubmit.html) method is called when the editing is completed. You are recommended to save the edited values to the underlying collection in this method. It makes sense to handle the entire editing operation in this single method. +The [DataGridSource.onCellSubmit](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/onCellSubmit.html) method is called when the editing is completed and validation passes. This is an asynchronous method where you should save the edited values to your underlying data collection. The UI automatically refreshes after changes are committed. ->**NOTE** - There is no need to call the `notifyListeners` after you update the DataGridRows. DataGrid will refresh the UI automatically. +> **Note:** There is no need to call the `notifyListeners` after you update the DataGridRows. DataGrid will refresh the UI automatically. {% tabs %} {% highlight dart %} @@ -438,10 +501,9 @@ class EmployeeDataSource extends DataGridSource { ### onCellCancelEdit -The [DataGridSource.onCellCancelEdit](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/onCellCancelEdit.html) method is called when you press the `Esc` key from Web and Desktop platforms. The [canSubmitCell](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/canSubmitCell.html) and [onCellSubmit](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/onCellSubmit.html) will not be called when the `Esc` key is pressed. +The [DataGridSource.onCellCancelEdit](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/onCellCancelEdit.html) method is called when editing is canceled. This occurs when the `Esc` key is pressed on Web and Desktop platforms. When this method is called, the [canSubmitCell](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/canSubmitCell.html) and [onCellSubmit](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/onCellSubmit.html) methods are not called. Focus returns to the DataGrid after cancellation. ->**NOTE** - No need to call the notifyListener inside it. +> **Note:** You do not need to call `notifyListeners` inside this method as the UI automatically handles state updates. {% tabs %} {% highlight dart %} @@ -544,6 +606,8 @@ The SfDataGrid allows moving the cell into edit mode programmatically by calling ![flutter datagrid begin edit](images/editing/begin_editing.gif) +> **Note:** Download the complete programmatic editing demo from [GitHub](https://github.com/SyncfusionExamples/how-to-perform-editing-in-flutter-datatable-sfdatagrid). + ### EndEdit The [SfDataGrid.endEdit](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/endEdit.html) method can be called to programmatically end the editing for a specific cell. @@ -629,7 +693,7 @@ The [SfDataGrid.endEdit](https://pub.dev/documentation/syncfusion_flutter_datagr ## How to check whether the current cell is in editing mode -You can check whether the current cell is in editing mode by using the [DataGridController.isCurrentCellInEditing](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/isCurrentCellInEditing.html) property. +You can check whether the current cell is in editing mode by using the [DataGridController.isCurrentCellInEditing](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/isCurrentCellInEditing.html) property. This read-only boolean property returns `true` if a cell is currently in edit mode, and `false` otherwise. {% tabs %} {% highlight dart %} @@ -721,9 +785,9 @@ You can check whether the current cell is in editing mode by using the [DataGrid {% endhighlight %} {% endtabs %} -## Restrict specific cell or column from being entered into edit mode at run time +## Prevent editing for specific cells or columns -To cancel the editing for a specific cell or column at run time, override the [onCellBeginEdit](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/onCellBeginEdit.html) method in the `DataGridSource` class and return false for a specific cell or column. +To prevent editing for specific cells or columns at runtime, override the [onCellBeginEdit](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/onCellBeginEdit.html) method in the `DataGridSource` class and return `false` for the cells or columns you want to protect. {% tabs %} {% highlight dart %} @@ -767,9 +831,7 @@ class EmployeeDataSource extends DataGridSource { ## Cancel edited cell value from being committed -You can override the [canSubmitCell](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/canSubmitCell.html) from the [DataGridSource](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource-class.html) class and return false based on your criteria. - -If you return a false from the `canSubmitCell` method, the Datagrid doesn't allow focus to move to other widgets outside the DataGrid. The focus will remain on the `currentCell`. +You can override the [canSubmitCell](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/canSubmitCell.html) method from the [DataGridSource](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource-class.html) class and return `false` based on your validation criteria. When `canSubmitCell` returns `false`, the edited cell retains focus and edit mode, preventing the user from navigating away until the input is corrected. {% tabs %} {% highlight dart %} @@ -794,15 +856,19 @@ class EmployeeDataSource extends DataGridSource { ## Perform editing asynchronously -Editing can be performed asynchronously by handling the [DataGridSource.canSubmitCell](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/canSubmitCell.html) method, which is called before the cell ends its editing and [DataGridSource.onCellSubmit](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/onCellSubmit.html), which is called when the cell ends its editing. +Editing can be performed asynchronously by implementing the [DataGridSource.canSubmitCell](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/canSubmitCell.html) method for validation and [DataGridSource.onCellSubmit](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/onCellSubmit.html) method for saving data. Both methods support `async` operations, allowing you to perform network requests or database operations. -The following example shows how to display a loading indicator for a specific amount of time when the cell ends its editing and also shows the loading indicator until the cell validates whether the entered value is valid. +The following example shows how to display a loading indicator during asynchronous validation and data persistence operations: {% tabs %} {% highlight Dart %} +import 'package:flutter/material.dart'; import 'package:syncfusion_flutter_datagrid/datagrid.dart'; +import 'dart:async'; +import 'package:collection/collection.dart'; +/// Global StreamController to manage loading state during async operations StreamController loadingController = StreamController(); List employees = []; @@ -917,12 +983,14 @@ class _MyHomePageState extends State { Future canSubmitCell(DataGridRow dataGridRow, RowColumnIndex rowColumnIndex, GridColumn column) async { if (column.columnName == 'id' && newCellValue == 104) { + // Show loading indicator during validation loadingController.add(true); + // Simulate server-side validation await Future.delayed(const Duration(seconds: 2)); loadingController.add(false); - return false; + return false; // Reject this specific value } else { - return true; + return true; // Allow submission for other values } } diff --git a/Flutter/datagrid/export-to-excel.md b/Flutter/datagrid/export-to-excel.md index 3fbe43daf..4a88a0c1e 100644 --- a/Flutter/datagrid/export-to-excel.md +++ b/Flutter/datagrid/export-to-excel.md @@ -1,7 +1,7 @@ --- layout: post title: Export Flutter DataGrid to Excel | Flutter DataTable | Syncfusion -description: Learn how to export the Syncfusion Flutter DataGrid (SfDataGrid) into Excel and more. +description: Learn how to export the Syncfusion Flutter DataGrid (SfDataGrid) to Excel and easily customize the exported worksheets. platform: flutter control: SfDataGrid documentation: ug @@ -19,32 +19,35 @@ The following dependencies must be added to your pubspec.yaml file for exporting dependencies: -syncfusion_flutter_datagrid_export: ^xx.x.xx +syncfusion_flutter_datagrid_export: ^24.1.41 {% endhighlight %} ->**NOTE:** Here, **xx.x.xx** denotes the current version of `Syncfusion Flutter DataGrid Export` package. +> **Note:** The version numbers shown above are examples. Refer to [pub.dev](https://pub.dev/packages/syncfusion_flutter_datagrid_export) for the latest stable version of `Syncfusion Flutter DataGrid Export` package. -**Import package** +**Import required packages** -Import the following package in your Dart code. +Import the following packages in your Dart code. {% tabs %} {% highlight Dart %} import 'package:syncfusion_flutter_datagrid_export/export.dart'; -import 'package:syncfusion_flutter_xlsio/xlsio.dart'; {% endhighlight %} {% endtabs %} -Export the `SfDataGrid` by using the following extension methods present in the [SfDataGridState](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGridState-class.html) class. +Export SfDataGrid by using the following extension methods present in the [SfDataGridState](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGridState-class.html) class: -* [exportToExcelWorkbook](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridExcelExportExtensions/exportToExcelWorkbook.html) -* [exportToExcelWorksheet](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridExcelExportExtensions/exportToExcelWorksheet.html) - +* [exportToExcelWorkbook](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridExcelExportExtensions/exportToExcelWorkbook.html) - Exports the grid to an Excel workbook +* [exportToExcelWorksheet](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridExcelExportExtensions/exportToExcelWorksheet.html) - Exports the grid to an existing Excel worksheet + +> **Note:** +>- File export requires platform-specific permissions. Ensure write permissions are configured in AndroidManifest.xml (Android), the iOS app configuration file, and the macOS entitlements file. +>- For web platforms, use web APIs instead of the `File` class. Consider using the `universal_html` package or browser download methods. +>- Refer to [getting-started](https://help.syncfusion.com/flutter/xlsio/getting-started) for platform-specific file generation code. -**Add GlobalKey for the DataGrid** +**Add GlobalKey for SfDataGrid** Create the [GlobalKey](https://api.flutter.dev/flutter/widgets/GlobalKey-class.html) using the `SfDataGridState` class. Exporting related methods are available in the `SfDataGridState` class. @@ -143,11 +146,15 @@ Widget build(BuildContext context) { ## Save the Excel document as a file -To save the file as an Excel document, it’s necessary to include [mobile](https://help.syncfusion.com/flutter/xlsio/getting-started#create-an-excel-document-in-mobile), [web](https://help.syncfusion.com/flutter/xlsio/getting-started#create-an-excel-document-in-web) and [desktop](https://help.syncfusion.com/flutter/xlsio/getting-started#create-an-excel-document-in-desktop) platform-specific file generating code. +Include platform-specific code to save the Excel document. Refer to the following sections for implementation details: + +* [Mobile (Android/iOS) file saving](https://help.syncfusion.com/flutter/xlsio/getting-started#create-an-excel-document-in-mobile) +* [Web file saving](https://help.syncfusion.com/flutter/xlsio/getting-started#create-an-excel-document-in-web) +* [Desktop (Windows/macOS/Linux) file saving](https://help.syncfusion.com/flutter/xlsio/getting-started#create-an-excel-document-in-desktop) ## Export DataGrid to Excel workbook -You can export the data to [Excel Workbook](https://pub.dev/documentation/syncfusion_flutter_xlsio/latest/xlsio/Workbook-class.html) by using the `exportToExcelWorkbook` method from the `key.currentState` of the DataGrid. +Export data to an [Excel Workbook](https://pub.dev/documentation/syncfusion_flutter_xlsio/latest/xlsio/Workbook-class.html) using the `exportToExcelWorkbook` method from the DataGrid's state. This creates a new workbook with the grid data. {% tabs %} {% highlight Dart %} @@ -161,7 +168,7 @@ File('DataGrid.xlsx').writeAsBytes(bytes, flush: true); ## Export DataGrid to Excel sheet -Export the data to [Excel Worksheet](https://pub.dev/documentation/syncfusion_flutter_xlsio/latest/xlsio/Worksheet-class.html) by using the `exportToExcelWorksheet` method from the `key.currentState` of the DataGrid. +Export data to an [Excel Worksheet](https://pub.dev/documentation/syncfusion_flutter_xlsio/latest/xlsio/Worksheet-class.html) using the `exportToExcelWorksheet` method. This appends grid data to an existing or new worksheet within a workbook. {% tabs %} {% highlight Dart %} @@ -175,11 +182,13 @@ File('DataGrid.xlsx').writeAsBytes(bytes, flush: true); {% endhighlight %} {% endtabs %} -## Exporting options +## Exporting options + +> **Note:** Export methods use XLSX format by default. Large datasets may consume significant memory during export—consider exporting selected rows for better performance with large grids. ### Exclude columns when exporting -By default, all the columns in the `SfDataGrid` are exported to Excel. To exclude certain columns when exporting to Excel, add those column names to the [excludeColumns](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToExcelConverter/excludeColumns.html) parameter. +By default, all columns in SfDataGrid are exported to Excel. Exclude specific columns by adding their names to the [excludeColumns](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToExcelConverter/excludeColumns.html) parameter. {% tabs %} {% highlight Dart %} @@ -195,7 +204,7 @@ final List bytes = workbook.saveAsStream(); ### Exclude table summaries when exporting -By default, table summaries in the `SfDataGrid` are exported to Excel. Set the [exportTableSummaries](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToExcelConverter/exportTableSummaries.html) parameter as `false` to export the `SfDataGrid` without table summaries. +By default, table summaries in SfDataGrid are exported to Excel. Set the [exportTableSummaries](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToExcelConverter/exportTableSummaries.html) parameter to `false` to exclude table summaries from the export. {% tabs %} {% highlight Dart %} @@ -209,7 +218,7 @@ final List bytes = workbook.saveAsStream(); ### Exclude stacked headers when exporting -By default, stacked headers in the `SfDataGrid` are exported to Excel. Set the [exportStackedHeaders](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToExcelConverter/exportStackedHeaders.html) parameter as `false` to export the `SfDataGrid` without stacked headers. +By default, stacked headers in SfDataGrid are exported to Excel. Set the [exportStackedHeaders](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToExcelConverter/exportStackedHeaders.html) parameter to `false` to exclude stacked headers from the export. {% tabs %} {% highlight Dart %} @@ -223,7 +232,7 @@ final List bytes = workbook.saveAsStream(); ### Change the start row and column index when exporting -By default, the DataGrid is exported from the (0,0) index in an Excel sheet. Export the data from a specific row and column indexes in an Excel worksheet by setting the [startColumnIndex](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToExcelConverter/startColumnIndex.html) and [startRowIndex](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToExcelConverter/startRowIndex.html) properties. +By default, the DataGrid is exported starting at cell (0,0) in the Excel sheet. Export data starting from a specific row and column by setting the [startRowIndex](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToExcelConverter/startRowIndex.html) and [startColumnIndex](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToExcelConverter/startColumnIndex.html) properties. {% tabs %} {% highlight Dart %} @@ -237,7 +246,7 @@ final List bytes = workbook.saveAsStream(); ## Export the selected rows to Excel -By default, the entire grid is exported to Excel. Export the selected rows only by passing the [dataGridController.selectedRows](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/selectedRows.html) to [rows](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/rows.html) parameter in `exportToExcelWorksheet` and `exportToExcelWorkbook` methods. +By default, the entire grid is exported to Excel. Export only selected rows by passing the [dataGridController.selectedRows](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/selectedRows.html) list to the `rows` parameter in the `exportToExcelWorksheet` or `exportToExcelWorkbook` methods. This parameter is optional; if omitted, all rows are exported. {% tabs %} {% highlight Dart %} @@ -251,9 +260,11 @@ final List bytes = workbook.saveAsStream(); ## Row height and column width customization -By default, [SfDataGrid.rowHeight](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/rowHeight.html) and [SfDataGrid.defaultColumnWidth](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/defaultColumnWidth.html) properties will be set to the cells in the Excel sheet. To customize the row height and column width in Excel, you can use the [defaultRowHeight](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToExcelConverter/defaultRowHeight.html) and [defaultColumnWidth](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToExcelConverter/defaultColumnWidth.html) properties. But these properties are only applicable when the [exportRowHeight](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToExcelConverter/exportRowHeight.html) and [exportColumnWidth](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToExcelConverter/exportColumnWidth.html) properties are `false`. +By default, the exported Excel cells use the [rowHeight](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/rowHeight.html) and [defaultColumnWidth](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/defaultColumnWidth.html) properties from SfDataGrid. -If the `exportRowHeight` and `exportColumnWidth` properties are `true`, the [SfDataGrid.headerRowHeight](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/headerRowHeight.html) and `SfDataGrid.rowHeight` properties are considered for row heights in Excel and the actual width of the column is considered for columns in Excel. +To use custom dimensions instead, set the [exportRowHeight](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToExcelConverter/exportRowHeight.html) and [exportColumnWidth](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToExcelConverter/exportColumnWidth.html) properties to `false`, then specify [defaultRowHeight](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToExcelConverter/defaultRowHeight.html) and [defaultColumnWidth](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToExcelConverter/defaultColumnWidth.html). + +When `exportRowHeight` and `exportColumnWidth` are `true`, the grid's [headerRowHeight](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/headerRowHeight.html), `rowHeight`, and actual column widths are exported to Excel. {% tabs %} {% highlight Dart %} @@ -270,7 +281,12 @@ final List bytes = workbook.saveAsStream(); ## Styling cells based on the cell type in Excel -Customize the cell styles based on cell type using the [cellExport](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToExcelConverter/cellExport.html) parameter, which is a callback in the `exportToExcelWorkbook` and `exportToExcelWorksheet` methods. +Customize cell styles during export using the [cellExport](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToExcelConverter/cellExport.html) callback parameter in the `exportToExcelWorkbook` or `exportToExcelWorksheet` methods. The callback provides access to [DataGridCellExcelExportDetails](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridCellExcelExportDetails-class.html) with cell type information: + +* `DataGridExportCellType.columnHeader` - Header cells +* `DataGridExportCellType.stackedHeaderCell` - Stacked header cells +* `DataGridExportCellType.row` - Data row cells +* `DataGridExportCellType.tableSummaryRow` - Summary row cells {% tabs %} {% highlight Dart %} @@ -294,7 +310,7 @@ final List bytes = workbook.saveAsStream(); ### Customize cell values while exporting -The cell value can be customized while exporting to Excel by directly setting the cell value to the [excelRange.value](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridCellExcelExportDetails/excelRange.html) property available in the argument of `cellExport` callback. +Customize cell values during export by setting the [excelRange.value](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridCellExcelExportDetails/excelRange.html) property in the `cellExport` callback. The supported value types include strings, numbers, dates, and booleans. Complex types are converted to their string representation. {% tabs %} {% highlight Dart %} @@ -313,9 +329,9 @@ final List bytes = workbook.saveAsStream(); ![excel shows the cell customization](images/export-to-excel/flutter-datagrid-excel-export-cell-customization.png) -### Customize the cells based on the column +### Customize cells based on the column -You can customize the column style based on the column name when exporting to Excel by using the [cellExport](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToExcelConverter/cellExport.html) parameter. +Customize cell styling by column using the [cellExport](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToExcelConverter/cellExport.html) callback. Access the column name via [details.columnName](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridCellExcelExportDetails/columnName.html) to apply styles to specific columns. {% tabs %} {% highlight Dart %} @@ -334,72 +350,74 @@ final List bytes = workbook.saveAsStream(); {% endhighlight %} {% endtabs %} -## Customize Exporting Behavior +## Customize Exporting Behavior -Customize the exporting behavior by overriding the available methods in the [DataGridToExcelConverter](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToExcelConverter-class.html) class. Use the `converter` parameter in the `exportToExcelWorksheet` or `exportToExcelWorkbook` method. +Customize export behavior by extending the [DataGridToExcelConverter](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToExcelConverter-class.html) class and overriding specific methods. Pass your custom converter to the `converter` parameter in the `exportToExcelWorksheet` or `exportToExcelWorkbook` method. + +> **Note:** Use `getCellValue` to transform cell data before export. Override `exportColumnHeader`, `exportRow`, or other export methods for advanced customization of specific row/column types. {% tabs %} {% highlight Dart %} class CustomDataGridToExcelConverter extends DataGridToExcelConverter { + /// Customize export of individual column header cells @override void exportColumnHeader(SfDataGrid dataGrid, GridColumn column, String columnName, Worksheet worksheet) { - // TODO: Add your requirements in exportColumnHeader super.exportColumnHeader(dataGrid, column, columnName, worksheet); } + /// Customize export of all column headers @override void exportColumnHeaders(SfDataGrid dataGrid, Worksheet worksheet) { - // TODO: Add your requirements in exportColumnHeaders super.exportColumnHeaders(dataGrid, worksheet); } + /// Customize export of individual row cells for each column @override void exportRow(SfDataGrid dataGrid, DataGridRow row, GridColumn column, Worksheet worksheet) { - // TODO: Add your requirements in exportRow super.exportRow(dataGrid, row, column, worksheet); } + /// Customize export of all data rows @override void exportRows( SfDataGrid dataGrid, List rows, Worksheet worksheet) { - // TODO: Add your requirements in exportRows super.exportRows(dataGrid, rows, worksheet); } + /// Customize export of individual stacked header rows @override void exportStackedHeaderRow(SfDataGrid dataGrid, StackedHeaderRow stackedHeaderRow, Worksheet worksheet) { - // TODO: Add your requirements in exportStackedHeaderRow super.exportStackedHeaderRow(dataGrid, stackedHeaderRow, worksheet); } + /// Customize export of all stacked header rows @override void exportStackedHeaderRows(SfDataGrid dataGrid, Worksheet worksheet) { - // TODO: Add your requirements in exportStackedHeaderRows super.exportStackedHeaderRows(dataGrid, worksheet); } + /// Customize export of individual table summary rows @override void exportTableSummaryRow(SfDataGrid dataGrid, GridTableSummaryRow summaryRow, Worksheet worksheet) { - // TODO: Add your requirements in exportTableSummaryRow super.exportTableSummaryRow(dataGrid, summaryRow, worksheet); } + /// Customize export of all table summary rows at specified positions @override void exportTableSummaryRows(SfDataGrid dataGrid, GridTableSummaryRowPosition position, Worksheet worksheet) { - // TODO: Add your requirements in exportTableSummaryRows super.exportTableSummaryRows(dataGrid, position, worksheet); } + /// Transform cell values before export (e.g., formatting, type conversion) @override Object? getCellValue(DataGridRow row, GridColumn column) { - // TODO: Add your requirements in getCellValue - super.getCellValue(row, column); + return super.getCellValue(row, column); } } @@ -416,4 +434,4 @@ Workbook workbook = key.currentState!.exportToExcelWorkbook(converter: converter final List bytes = workbook.saveAsStream(); {% endhighlight %} -{% endtabs %} +{% endtabs %} \ No newline at end of file diff --git a/Flutter/datagrid/export-to-pdf.md b/Flutter/datagrid/export-to-pdf.md index ad5bf1a36..75f1615be 100644 --- a/Flutter/datagrid/export-to-pdf.md +++ b/Flutter/datagrid/export-to-pdf.md @@ -23,11 +23,13 @@ syncfusion_flutter_datagrid_export: ^xx.x.xx {% endhighlight %} - >**NOTE** Here, **xx.x.xx** denotes the current version of `Syncfusion® Flutter DataGrid Export` package. +> **Note:** +>- Here, **xx.x.xx** denotes the current version of `Syncfusion® Flutter DataGrid Export` package. Find the latest version on [pub.dev](https://pub.dev/packages/syncfusion_flutter_datagrid_export). +>- Supported on Android, iOS, web, macOS, and Windows platforms. **Import package** -Import the following package in your Dart code. +Import the following packages in your Dart code. {% tabs %} {% highlight Dart %} @@ -40,7 +42,7 @@ import 'package:syncfusion_flutter_pdf/pdf.dart'; {% endtabs %} -You can export the `SfDataGrid` to PDF by using the following extension methods present in the [SfDataGridState]((https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGridState-class.html)) class: +You can export the `SfDataGrid` to PDF by using the following extension methods present in the [SfDataGridState](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGridState-class.html) class: * [exportToPdfDocument](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridPdfExportExtensions/exportToPdfDocument.html) * [exportToPdfGrid](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridPdfExportExtensions/exportToPdfGrid.html) @@ -49,6 +51,8 @@ You can export the `SfDataGrid` to PDF by using the following extension methods Create a [GlobalKey](https://api.flutter.dev/flutter/widgets/GlobalKey-class.html) using the `SfDataGridState` class. Exporting related methods are available via `SfDataGridState` class. +> **Note:** The GlobalKey must be assigned to the SfDataGrid widget to access export functionality. Without it, the export methods will not be available. + Set the created `GlobalKey` to the `SfDataGrid`. {% tabs %} @@ -128,10 +132,6 @@ The following code illustrates how to create and display a `SfDataGrid` using th {% endhighlight %} {% endtabs %} -## Save the PDF document as a file - -To save the file as a PDF document, it’s necessary to include [mobile](https://help.syncfusion.com/flutter/pdf/getting-started#save-and-open-a-pdf-document-in-mobile), [web](https://help.syncfusion.com/flutter/pdf/getting-started#save-and-download-a-pdf-document-in-web) and desktop platform-specific file generating code. - ## Export DataGrid to PDF document Export the data to the [PdfDocument](https://pub.dev/documentation/syncfusion_flutter_pdf/latest/pdf/PdfDocument-class.html) by using the `exportToPdfDocument` method from the `key.currentState` of the DataGrid. @@ -170,7 +170,7 @@ File('DataGrid.pdf').writeAsBytes(bytes); ### Exclude columns when exporting -By default, all the columns in the SfDataGrid are exported to PDF. To exclude some particular columns while exporting to PDF, add those column names to the [excludeColumns](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToPdfConverter-class.html) parameter. +By default, all the columns in the `SfDataGrid` are exported to PDF. To exclude some particular columns while exporting to PDF, add those column names to the [excludeColumns](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToPdfConverter/excludeColumns.html) parameter of the `exportToPdfDocument` or `exportToPdfGrid` method. {% tabs %} {% highlight Dart %} @@ -198,7 +198,7 @@ final List bytes = document.saveSync(); ### Export all columns on one page -Fit all the columns on one page by setting the [fitAllColumnsInOnePage](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToPdfConverter/fitAllColumnsInOnePage.html) parameter as `true.` +Fit all the columns on one page by setting the [fitAllColumnsInOnePage](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToPdfConverter/fitAllColumnsInOnePage.html) parameter as `true`. {% tabs %} {% highlight Dart %} @@ -209,9 +209,11 @@ final List bytes = document.saveSync(); {% endhighlight %} {% endtabs %} +> **Note:** When `fitAllColumnsInOnePage` is enabled, it takes priority over `autoColumnWidth`. If you need to use actual column widths, ensure `fitAllColumnsInOnePage` is `false`. + ### Exclude table summaries when exporting -By default, table summaries in `SfDataGrid` are exported to PDF. Set the [exportTableSummaries](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToPdfConverter/exportTableSummaries.html) parameter as `false` to export the `SfDataGrid` without table summaries. +By default, table summaries in `SfDataGrid` are exported to PDF. Set the [exportTableSummaries](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToPdfConverter/exportTableSummaries.html) parameter as `false` to export the `SfDataGrid` without table summaries (if applicable to your data source). {% tabs %} {% highlight Dart %} @@ -225,7 +227,7 @@ final List bytes = document.saveSync(); ### Exclude stacked headers when exporting -By default, stacked headers in `SfDataGrid` are exported to PDF. Set the [exportStackedHeaders](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToPdfConverter/exportStackedHeaders.html) parameter as `false` to export the `SfDataGrid` without stacked headers. +By default, stacked headers in `SfDataGrid` are exported to PDF. Set the [exportStackedHeaders](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToPdfConverter/exportStackedHeaders.html) parameter as `false` to export the `SfDataGrid` without stacked headers (if applicable to your data source). {% tabs %} {% highlight Dart %} @@ -238,24 +240,23 @@ final List bytes = document.saveSync(); ### Auto-size column widths in PDF -In order, to export the actual column width from `SfDataGrid` instead of the auto column width, set the [autoColumnWidth](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToPdfConverter/autoColumnWidth.html) parameter as `false`. +In order to export the actual column width from `SfDataGrid` instead of the auto column width, set the [autoColumnWidth](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToPdfConverter/autoColumnWidth.html) parameter as `false`. {% tabs %} {% highlight Dart %} -PdfDocument document = key.currentState!.exportToPdfDocument(autoColumnWidth: false); +PdfDocument document = key.currentState!.exportToPdfDocument(autoColumnWidth: false, fitAllColumnsInOnePage: false); final List bytes = document.saveSync(); {% endhighlight %} {% endtabs %} ->**NOTE** - If you disabled the `autoColumnWidth`, then you must set `fitAllColumnsInOnePage` as false. Then only, the overflowing columns are drawn in next page. Because `fitAllColumnsInOnePage` has topmost priority. +> **Note:** If you disable `autoColumnWidth`, you must also set `fitAllColumnsInOnePage` as `false` to allow overflowing columns to be drawn on subsequent pages. ## Change the orientation of the PDF document -Change the orientation of a page in a PDF document by using the [PdfDocument.pageSettings.orientation](https://pub.dev/documentation/syncfusion_flutter_pdf/latest/pdf/PdfPageSettings/orientation.html) property. +Change the orientation of a page in a PDF document by using the [PdfPageSettings.orientation](https://pub.dev/documentation/syncfusion_flutter_pdf/latest/pdf/PdfPageSettings/orientation.html) property. To change the page orientation, you need to export the `SfDataGrid` to `PdfGrid` using the `exportToPdfGrid` method and draw the exported `PdfGrid` into a `PdfDocument`. @@ -276,7 +277,9 @@ final List bytes = document.saveSync(); ## Export the selected rows to PDF -By default, the entire grid is exported to PDF. Export the selected rows only by passing the [dataGridController.selectedRows](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/selectedRows.html) to [rows](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/rows.html) parameter in `exportToPdfDocument` and `exportToPdfGrid` methods. +By default, the entire grid is exported to PDF. Export the selected rows only by passing the [dataGridController.selectedRows](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/selectedRows.html) collection to the [rows](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/rows.html) parameter in `exportToPdfDocument` and `exportToPdfGrid` methods. + +> **Note:** If no rows are selected, the entire grid will be exported. Ensure rows are selected before calling the export method if you only want selected data. {% tabs %} {% highlight Dart %} @@ -293,6 +296,8 @@ final List bytes = document.saveSync(); Setting the [PdfPageTemplateElement](https://pub.dev/documentation/syncfusion_flutter_pdf/latest/pdf/PdfPageTemplateElement-class.html) to [headerFooterExport.pdfDocumentTemplate.top](https://pub.dev/documentation/syncfusion_flutter_pdf/latest/pdf/PdfDocumentTemplate/top.html) loads the content at the top of the page, while setting the `PdfPageTemplateElement` to [headerFooterExport.pdfDocumentTemplate.bottom](https://pub.dev/documentation/syncfusion_flutter_pdf/latest/pdf/PdfDocumentTemplate/bottom.html) loads the content at the bottom of the page. +> **Note:** Headers and footers defined via templates will be repeated on every page of the multi-page PDF document. + {% tabs %} {% highlight Dart %} @@ -318,7 +323,9 @@ final List bytes = document.saveSync(); ## Styling cells based on the cell type in PDF -You can customize the cell styles based on cell type using the [cellExport](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToPdfConverter/cellExport.html) parameter, which is a callback in `exportToPdfDocument` or `exportToPdfGrid` methods. +You can customize the cell styles based on cell type using the [cellExport](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToPdfConverter/cellExport.html) parameter, which is a callback function in `exportToPdfDocument` or `exportToPdfGrid` methods. This callback is invoked for each cell during export, allowing you to modify styles and values dynamically. + +> **Note:** When both cell value and cell style properties are modified in the `cellExport` callback, both modifications are applied to the exported PDF cell. {% tabs %} {% highlight Dart %} @@ -382,7 +389,9 @@ final List bytes = document.saveSync(); ## Customize Exporting Behavior -Customize the exporting behavior by overriding the available methods in the [DataGridToPdfConverter](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToPdfConverter-class.html) class. Use the `converter` parameter in the `exportToPdfDocument` or `exportToPdfGrid` method. +For advanced export scenarios beyond the standard customization options, customize the exporting behavior by overriding the available methods in the [DataGridToPdfConverter](https://pub.dev/documentation/syncfusion_flutter_datagrid_export/latest/syncfusion_flutter_datagrid_export/DataGridToPdfConverter-class.html) class. Use the `converter` parameter in the `exportToPdfDocument` or `exportToPdfGrid` method. + +> **Note:** Use custom converters when you need to modify the export logic for column headers, rows, or data formatting beyond what the standard parameters provide. {% tabs %} {% highlight Dart %} @@ -391,31 +400,27 @@ class CustomDataGridToPdfConverter extends DataGridToPdfConverter { @override void exportColumnHeader(SfDataGrid dataGrid, GridColumn column, String columnName, PdfGrid pdfGrid) { - // TODO: Add your requirements column header - + // Custom implementation for individual column header export super.exportColumnHeader(dataGrid, column, columnName, pdfGrid); } @override void exportColumnHeaders( SfDataGrid dataGrid, List columns, PdfGrid pdfGrid) { - // TODO: Add your requirements column headers - + // Custom implementation for all column headers export super.exportColumnHeaders(dataGrid, columns, pdfGrid); } @override void exportRows( List columns, List rows, PdfGrid pdfGrid) { - // TODO: Add your requirements in exportRows - + // Custom implementation for exporting multiple rows super.exportRows(columns, rows, pdfGrid); } @override void exportRow(List columns, DataGridRow row, PdfGrid pdfGrid) { - // TODO: Add your requirements in exportRow - + // Custom implementation for exporting individual row super.exportRow(columns, row, pdfGrid); } } diff --git a/Flutter/datagrid/filtering.md b/Flutter/datagrid/filtering.md index aae9c7547..6a523990c 100644 --- a/Flutter/datagrid/filtering.md +++ b/Flutter/datagrid/filtering.md @@ -9,12 +9,14 @@ documentation: ug # Filtering in Flutter DataGrid (SfDataGrid) -Filtering is the process of fetching the values from a collection that satisfy specified condition. In the [SfDataGrid](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid-class.html), filtering can be applied both through the UI and programmatically. +Filtering is the process of fetching values from a collection that satisfy specified conditions. In the [SfDataGrid](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid-class.html), filtering can be applied both through the UI and programmatically. ## Programmatic Filtering The SfDataGrid allows you to filter the data rows programmatically by adding filter conditions along with their respective column names to the [DataGridSource.filterConditions](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/filterConditions.html) map collection. In the map collection, the `key` defines the [columnName](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn/columnName.html) and the `values` define the list of [FilterCondition](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/FilterCondition-class.html). +> **Note:** To use programmatic filtering, you must have a custom class that extends [DataGridSource](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource-class.html) with properly initialized data rows. + `DataGridSource.filterConditions` is an unmodifiable map collection. So, it doesn't allow us to perform CRUD operations directly in the `DataGridSource.filterConditions` property. However, it can be done by the following public methods: ### Add filter @@ -255,10 +257,10 @@ Filter conditions can be cleared from all columns using the [DataGridSource.clea ### Filter behavior -The [FilterBehavior](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/FilterBehavior.html) property specifies whether filtering should consider cell values as strings or by their actual data types. +The [FilterBehavior](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/FilterBehavior.html) property specifies whether filtering should consider cell values as strings or by their actual data types. This property is set in the [FilterCondition](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/FilterCondition-class.html) object. -* **stringDataType** - Converts the cell value to a string data type before comparing. -* **strongDataType** - Compares the cell value using its actual data type. +* **stringDataType** - Converts the cell value to a string data type before comparing. Use this for case-insensitive or partial text matching. +* **strongDataType** - Compares the cell value using its actual data type (e.g., numeric, DateTime). Use this for precise type-specific filtering. {% tabs %} {% highlight Dart %} @@ -527,12 +529,15 @@ After filtering, you can retrieve the rows in the same order as displayed in the ## UI Filtering -`SfDataGrid` provides an Excel-like filtering UI and an advanced filter UI for easy data filtering. UI filtering can be enabled by setting the [SfDataGrid.allowFiltering](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/allowFiltering.html) property to `true.` This allows the filter UI to be opened by clicking the filter icon in the column header. The filtering UI appears as a popup menu on desktop and web platforms, and as a new page on mobile platforms. +`SfDataGrid` provides an Excel-like filtering UI and an advanced filter UI for easy data filtering. UI filtering can be enabled by setting the [SfDataGrid.allowFiltering](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/allowFiltering.html) property to `true`. This allows the filter UI to be opened by clicking the filter icon in the column header. + +> **Note:** +> - **Platform-specific behavior:** The filtering UI appears as a popup menu on desktop and web platforms, and as a new page on mobile platforms. -The `SfDataGrid` provides the following types of filter popup modes: +The `SfDataGrid` provides the following types of filter UI modes: -* **Checkbox Filter** - Provides excel like filter interface with a list of checkboxes. -* **Advanced Filter** - Provides advanced filter options to filter the data with multiple conditions. +* **Checkbox Filter** - Provides an Excel-like filter interface with a list of checkboxes for selecting specific values. +* **Advanced Filter** - Provides advanced filter options to filter data with multiple conditions using filter types and operators. The following image shows the checkbox filter popup menu on the web and desktop platforms, @@ -599,9 +604,9 @@ The following image shows the filtered data rows which are filtered by the advan Flutter datagrid shows the filtered rows -#### Case sensitive filtering +#### Case-sensitive filtering -Case-sensitive filtering can be enabled for the column using the casing icon available in the advanced filter UI. This is available only for the `TextFilters` filter view. If the icon is active, the filtering will be applied with the case sensitive with the filter text. The case-sensitive icon will be shown only to the string-type columns. +Case-sensitive filtering can be enabled for the column using the case-sensitive icon available in the advanced filter UI. This option is available only for text-based columns. When enabled, the filter comparison will be case-sensitive with respect to the filter text. The following image shows the advanced filter popup menu with a case-sensitive icon, @@ -609,137 +614,124 @@ The following image shows the advanced filter popup menu with a case-sensitive i ### Disable filtering for an individual column -The [GridColumn.allowFiltering](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn/allowFiltering.html) has a higher priority than the `SfDataGrid.allowFiltering` property. So, you can disable the filtering for any particular column by setting the `GridColumn.allowFiltering` property to `false`. +The [GridColumn.allowFiltering](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn/allowFiltering.html) property has a higher priority than the `SfDataGrid.allowFiltering` property. Disable filtering for any particular column by setting the `GridColumn.allowFiltering` property to `false`. {% tabs %} {% highlight Dart %} +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; + @override Widget build(BuildContext context) { - return SfDataGrid( - allowFiltering: true, - source: _employeeDataSource, - columns: [ - GridColumn( - allowFiltering: false, - 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, - ) - ) - ), - ] + return Scaffold( + body: SfDataGrid( + allowFiltering: true, + source: _employeeDataSource, + columnWidthMode: ColumnWidthMode.fill, + columns: [ + GridColumn( + allowFiltering: false, + 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), + ), + ), + ], + ), ); } {% endhighlight %} {% endtabs %} -## Callbacks +## Filtering Callbacks -The SfDataGrid provides the following callbacks to notify the filtering stages: +The SfDataGrid provides callbacks to notify the filtering stages. These callbacks allow you to customize the filtering behavior and access filter condition details. ### OnFilterChanging callback -[onFilterChanging](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/onFilterChanging.html) callback invokes when the filtering is being applied to the particular column through UI filtering. You can return `false` from this callback to restrict the column from being filtered. +The [onFilterChanging](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/onFilterChanging.html) callback is invoked when filtering is being applied to a particular column through UI filtering. Return `false` from this callback to prevent filtering on that column. {% tabs %} {% highlight Dart %} +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; + @override Widget build(BuildContext context) { - return SfDataGrid( - allowFiltering: true, - source: _employeeDataSource, - onFilterChanging: (DataGridFilterChangeDetails details) { - if (details.column.columnName == 'Salary') { - return false; - } - return true; - }, - 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, - ) - ) - ), - ] + return Scaffold( + body: SfDataGrid( + source: _employeeDataSource, + allowFiltering: true, + onFilterChanging: (DataGridFilterChangeDetails details) { + // Restrict filtering on the Salary column + if (details.column.columnName == 'salary') { + return false; + } + return true; + }, + columnWidthMode: ColumnWidthMode.fill, + columns: [ + 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', overflow: TextOverflow.ellipsis), + ), + ), + GridColumn( + columnName: 'salary', + label: Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.center, + child: Text('Salary'), + ), + ), + ], + ), ); } @@ -748,67 +740,62 @@ The SfDataGrid provides the following callbacks to notify the filtering stages: ### OnFilterChanged callback -The [onFilterChanged](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/onFilterChanged.html) callback is invoked after filtering is applied to a particular column through UI filtering. You can use this callback to access filter conditions. +The [onFilterChanged](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/onFilterChanged.html) callback is invoked after filtering is applied to a particular column through UI filtering. Use this callback to access filter condition details such as the column name, filter type, and filter value. {% tabs %} {% highlight Dart %} +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; + @override Widget build(BuildContext context) { - return SfDataGrid( - allowFiltering: true, - source: _employeeDataSource, - onFilterChanged: (DataGridFilterChangeDetails details) { - print('Column Name: ${details.column.columnName}'); - print('Filter Type: ${details.filterConditions.last.type}'); - print('Filter Value: ${details.filterConditions.last.value}'); - }, - 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, - ) - ) - ), - ] + return Scaffold( + body: SfDataGrid( + source: _employeeDataSource, + allowFiltering: true, + onFilterChanged: (DataGridFilterChangeDetails details) { + debugPrint('Column Name: ${details.column.columnName}'); + if (details.filterConditions.isNotEmpty) { + debugPrint('Filter Type: ${details.filterConditions.last.type}'); + debugPrint('Filter Value: ${details.filterConditions.last.value}'); + } + }, + columnWidthMode: ColumnWidthMode.fill, + columns: [ + 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', overflow: TextOverflow.ellipsis), + ), + ), + GridColumn( + columnName: 'salary', + label: Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.center, + child: Text('Salary'), + ), + ), + ], + ), ); } @@ -817,7 +804,9 @@ The [onFilterChanged](https://pub.dev/documentation/syncfusion_flutter_datagrid/ ## Customizing the filter popup menu options -The `SfDataGrid` provides support to customize the menu options in the filter popup menu. Please refer to the following topics for more information. +The `SfDataGrid` provides support to customize the behavior and appearance of the filter popup menu. The following subsections demonstrate how to customize various aspects of the filter UI. + +> **Note:** Filter UI customization options like `filterMode`, `canShowSortingOptions`, and `canShowClearFilterOption` are available through the [FilterPopupMenuOptions](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/FilterPopupMenuOptions-class.html) class in the [GridColumn.filterPopupMenuOptions](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn/filterPopupMenuOptions.html) property. ### Show checkbox or advanced filtering mode @@ -1155,11 +1144,9 @@ import 'package:syncfusion_flutter_datagrid/datagrid.dart'; ### Set a custom filter icon -The `SfDataGrid` allows you to change the filter icon by using the [SfDataGridThemeData.filterIcon](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/filterIcon.html) property. The DataGrid should be wrapped inside the `SfDataGridTheme.` - -The `SfDataGridThemeData` and `SfDataGridTheme` classes are available in the [syncfusion_flutter_core](https://pub.dev/packages/syncfusion_flutter_core) package. So, import the following file. +The `SfDataGrid` allows you to change the filter icon by using the [SfDataGridThemeData.filterIcon](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/filterIcon.html) property. The `SfDataGridThemeData` and `SfDataGridTheme` classes are available in the [syncfusion_flutter_core](https://pub.dev/packages/syncfusion_flutter_core) package. -By using the [Builder](https://api.flutter.dev/flutter/widgets/Builder-class.html) widget, change the icon based on each state of the filtering, that is, the filter and filtered states. You must return the icons for two states even if you want to change the icon for a specific state. +> **Note:** Wrap the `SfDataGrid` inside an `SfDataGridTheme` widget to apply custom filter icons. Use a [Builder](https://api.flutter.dev/flutter/widgets/Builder-class.html) widget to return different icons based on filter states (filtered or not filtered). {% tabs %} {% highlight Dart %} @@ -1242,7 +1229,7 @@ import 'package:syncfusion_flutter_datagrid/datagrid.dart'; ## Change the position of the filter icon -The position of the filter icon can be changed by using the [GridColumn.filterIconPosition](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn/filterIconPosition.html) property. +The position of the filter icon can be changed by using the [GridColumn.filterIconPosition](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn/filterIconPosition.html) property. The icon can be positioned at the start or end of the column header using the [ColumnHeaderIconPosition](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/ColumnHeaderIconPosition.html) enum. {% tabs %} {% highlight Dart %} @@ -1252,47 +1239,55 @@ import 'package:syncfusion_flutter_datagrid/datagrid.dart'; @override Widget build(BuildContext context) { return Scaffold( - body: SfDataGrid( - source: _employeeDataSource, + body: SfDataGrid( + source: employeeDataSource, allowFiltering: true, gridLinesVisibility: GridLinesVisibility.both, headerGridLinesVisibility: GridLinesVisibility.both, + columnWidthMode: ColumnWidthMode.fill, columns: [ GridColumn( - filterIconPosition: ColumnHeaderIconPosition.start, - columnName: 'id', - label: Container( - padding: EdgeInsets.symmetric(horizontal: 8.0), - alignment: Alignment.centerRight, - child: Text( - 'ID', - overflow: TextOverflow.ellipsis, - ))), + filterIconPosition: ColumnHeaderIconPosition.start, + columnName: 'id', + label: Container( + padding: EdgeInsets.symmetric(horizontal: 8.0), + alignment: Alignment.centerRight, + child: Text( + 'ID', + overflow: TextOverflow.ellipsis, + ), + ), + ), GridColumn( - columnName: 'name', - label: Container( - padding: EdgeInsets.symmetric(horizontal: 8.0), - alignment: Alignment.centerLeft, - child: Text( - 'Name', - overflow: TextOverflow.ellipsis, - ))), + columnName: 'name', + label: Container( + padding: EdgeInsets.symmetric(horizontal: 8.0), + alignment: Alignment.centerLeft, + child: Text( + 'Name', + overflow: TextOverflow.ellipsis, + ), + ), + ), GridColumn( - columnName: 'designation', - label: Container( - padding: EdgeInsets.all(8.0), - alignment: Alignment.centerLeft, - child: Text( - 'Designation', - overflow: TextOverflow.ellipsis, - ))), + columnName: 'designation', + label: Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.centerLeft, + child: Text( + 'Designation', + overflow: TextOverflow.ellipsis, + ), + ), + ), GridColumn( - columnName: 'salary', - label: Container( - padding: EdgeInsets.all(8.0), - alignment: Alignment.centerRight, - child: Text('Salary' - ))), + columnName: 'salary', + label: Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.centerRight, + child: Text('Salary'), + ), + ), ], ), ); @@ -1307,6 +1302,8 @@ import 'package:syncfusion_flutter_datagrid/datagrid.dart'; The text style of the filter popup menu can be customized by using the [SfDataGridThemeData.filterPopupTextStyle](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/filterPopupTextStyle.html) and [SfDataGridThemeData.filterPopupDisabledTextStyle](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/filterPopupDisabledTextStyle.html) properties. +> **Note:** Wrap the `SfDataGrid` inside an `SfDataGridTheme` widget to apply text style customizations. + {% tabs %} {% highlight Dart %} @@ -1316,57 +1313,58 @@ import 'package:syncfusion_flutter_core/theme.dart'; @override Widget build(BuildContext context) { return Scaffold( - body: SfDataGridTheme( - data: SfDataGridThemeData( - filterPopupTextStyle:GoogleFonts.sacramento( - textStyle: const TextStyle( - fontSize: 25 - )), - filterPopupDisabledTextStyle: GoogleFonts.abhayaLibre( - textStyle: const TextStyle( - fontSize:25 - )),), - child: SfDataGrid( - source: _employeeDataSource, - allowFiltering: true, - columns: [ - GridColumn( + body: SfDataGridTheme( + data: SfDataGridThemeData( + filterPopupTextStyle: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + ), + filterPopupDisabledTextStyle: const TextStyle( + fontSize: 14, + color: Colors.grey, + ), + ), + child: SfDataGrid( + source: _employeeDataSource, + allowFiltering: true, + columnWidthMode: ColumnWidthMode.fill, + columns: [ + GridColumn( columnName: 'id', label: Container( - padding: EdgeInsets.symmetric(horizontal: 8.0), - alignment: Alignment.centerRight, - child: Text( - 'ID', - overflow: TextOverflow.ellipsis, - ))), - GridColumn( + padding: EdgeInsets.symmetric(horizontal: 8.0), + alignment: Alignment.centerRight, + child: Text('ID', overflow: TextOverflow.ellipsis), + ), + ), + GridColumn( columnName: 'name', label: Container( - padding: EdgeInsets.symmetric(horizontal: 8.0), - alignment: Alignment.centerLeft, - child: Text( - 'Name', - overflow: TextOverflow.ellipsis, - ))), - GridColumn( + padding: EdgeInsets.symmetric(horizontal: 8.0), + alignment: Alignment.centerLeft, + child: Text('Name', overflow: TextOverflow.ellipsis), + ), + ), + GridColumn( columnName: 'designation', label: Container( - padding: EdgeInsets.all(8.0), - alignment: Alignment.centerLeft, - child: Text( - 'Designation', - overflow: TextOverflow.ellipsis, - ))), - GridColumn( + padding: EdgeInsets.all(8.0), + alignment: Alignment.centerLeft, + child: Text('Designation', overflow: TextOverflow.ellipsis), + ), + ), + GridColumn( columnName: 'salary', label: Container( - padding: EdgeInsets.all(8.0), - alignment: Alignment.centerRight, - child: Text('Salary' - ))), - ], + padding: EdgeInsets.all(8.0), + alignment: Alignment.centerRight, + child: Text('Salary'), + ), + ), + ], + ), ), - )); + ); } {% endhighlight %} @@ -1520,9 +1518,7 @@ By default, the `FilterBehavior.strongDataType` applies to numeric, String, and The `SfDataGrid` provides complete color customization support for the filter popup menu, allowing you to personalize its appearance and enhance its visual appeal. -You can apply custom colors and personalize the filter popup menu by configuring the properties listed below through the `SfDataGridTheme`. To enable this, ensure that the `SfDataGrid` is wrapped inside an `SfDataGridTheme` widget. - -The `SfDataGridThemeData` and `SfDataGridTheme` classes are available in the [syncfusion_flutter_core](https://pub.dev/packages/syncfusion_flutter_core) package. So, make sure to import the following file. +> **Note:** The `SfDataGrid` must be wrapped inside an `SfDataGridTheme` widget for appearance customizations to take effect. The `SfDataGridThemeData` and `SfDataGridTheme` classes are available in the [syncfusion_flutter_core](https://pub.dev/packages/syncfusion_flutter_core) package. | Properties | Description | @@ -1562,8 +1558,7 @@ The `SfDataGridThemeData` and `SfDataGridTheme` classes are available in the [sy | `searchAreaFocusedBorderColor` | Use the [SfDataGridThemeData.searchAreaFocusedBorderColor](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/searchAreaFocusedBorderColor.html) property to define the focused border color of the search area in the filter popup menu | | `searchIconColor` | The color of the search icon in the search area of the filter popup menu can be customized using the [SfDataGridThemeData.searchIconColor](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/searchIconColor.html) property. | -> **NOTE** - The `cancelFilteringLabelColor`, `filterPopupBottomDividerColor`, and `okFilteringLabelColor` properties are supported only on desktop platforms. +> **Note:** The `cancelFilteringLabelColor`, `filterPopupBottomDividerColor`, and `okFilteringLabelColor` properties are supported only on desktop platforms. The following example shows how to customize the filter popup menu using properties from `SfDataGridTheme`, such as `cancelFilteringLabelButtonColor`, `cancelFilteringLabelColor`, `okFilteringLabelButtonColor`, `okFilteringLabelColor`, `filterPopupCheckboxFillColor`, and `filterPopupDisabledIconColor`. diff --git a/Flutter/datagrid/footer.md b/Flutter/datagrid/footer.md index 70294bbf5..30525c6df 100644 --- a/Flutter/datagrid/footer.md +++ b/Flutter/datagrid/footer.md @@ -9,7 +9,9 @@ documentation: ug # Footer in Flutter DataGrid (SfDataGrid) -Creates an additional row that can be displayed under the last row. Widgets can be displayed in the additional row by setting the [SfDataGrid.footer](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/footer.html) property. +The footer row is an additional row that displays below the last data row in the grid. Widgets can be displayed in the footer row by setting the [SfDataGrid.footer](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/footer.html) property. + +> **Note:** Before implementing the footer functionality, ensure you have set up the SfDataGrid with a valid [DataGridSource](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource-class.html) and configured the necessary columns. {% tabs %} {% highlight Dart %} @@ -74,7 +76,9 @@ Creates an additional row that can be displayed under the last row. Widgets can ## Change the footer row height -An additional row height can be personalized by using the [SfDataGrid.footerHeight](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/footerHeight.html) property. The default value of the additional row is 49.0. +The footer row height can be customized by using the [SfDataGrid.footerHeight](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/footerHeight.html) property. The default height of the footer row is 49.0 logical pixels. + +> **NOTE:** When setting a custom footer height, ensure it is sufficient to display all the content without text overflow or clipping. {% tabs %} {% highlight Dart %} @@ -131,7 +135,9 @@ An additional row height can be personalized by using the [SfDataGrid.footerHeig ## Show the footer row always -By default, the additional row will be displayed below the last row. To show the additional row always on the view bottom, simply set the [SfDataGrid.footerFrozenRowsCount](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/footerFrozenRowsCount.html) property to 1. +By default, the footer row is displayed below the last data row. To keep the footer visible at the bottom of the grid while scrolling vertically, set the [SfDataGrid.footerFrozenRowsCount](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/footerFrozenRowsCount.html) property to 1. + +> **NOTE:** Setting `footerFrozenRowsCount` to 1 freezes the footer row, ensuring it remains visible when users scroll through the data, similar to freezing header rows. {% tabs %} {% highlight Dart %} diff --git a/Flutter/datagrid/freeze-panes.md b/Flutter/datagrid/freeze-panes.md index 83c1746ff..a0f82bf0f 100644 --- a/Flutter/datagrid/freeze-panes.md +++ b/Flutter/datagrid/freeze-panes.md @@ -29,7 +29,7 @@ Set the frozen rows count at the top of the SfDataGrid. footerFrozenRowsCount -Set the footer rows count at the bottom of the SfDataGrid. +Set the footer frozen rows count at the bottom of the SfDataGrid. @@ -45,7 +45,31 @@ Set the frozen columns count on the left side of the SfDataGrid. footerFrozenColumnsCount -Set the footer columns on the right side of the SfDataGrid. +Set the footer frozen columns on the right side of the SfDataGrid. + + + + +frozenPaneElevation + + +Customize the elevation effect applied to frozen panes. Default value is 5.0. Set to 0.0 to remove elevation and display only the frozen pane line. + + + + +frozenPaneLineColor + + +Customize the color of the line displayed at the edge of frozen panes. + + + + +frozenPaneLineWidth + + +Customize the width of the line displayed at the edge of frozen panes. @@ -54,11 +78,14 @@ Set the footer columns on the right side of the SfDataGrid. The columns can be frozen in view at left and right like Excel by setting the [frozenColumnsCount](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/frozenColumnsCount.html) and [footerFrozenColumnsCount](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/footerFrozenColumnsCount.html) properties. -The following code example shows how to freeze a column at left using `frozenColumnsCount`, +The following code example shows how to freeze a column at left using `frozenColumnsCount`: {% tabs %} {% highlight Dart %} +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; + @override Widget build(BuildContext context) { return Scaffold( @@ -147,11 +174,14 @@ The following code example shows how to freeze a column at left using `frozenCol ![flutter datagrid shows frozen column at left](images/frozen-pane/flutter-datagrid-frozen-column.gif) -The following code example shows how to freeze a column at right using the `footerFrozenColumnsCount.` +The following code example shows how to freeze a column at right using the `footerFrozenColumnsCount`: {% tabs %} {% highlight Dart %} +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; + @override Widget build(BuildContext context) { return Scaffold( @@ -249,11 +279,14 @@ The following code example shows how to freeze a column at right using the `foot The rows can be frozen in view at the top and bottom like in Excel by setting the [frozenRowsCount](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/frozenRowsCount.html) and [footerFrozenRowsCount](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/footerFrozenRowsCount.html) properties. -The following code example shows how to freeze a row at the top using the `frozenRowsCount`, +The following code example shows how to freeze a row at the top using the `frozenRowsCount`: {% tabs %} {% highlight Dart %} +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; + @override Widget build(BuildContext context) { return Scaffold( @@ -341,11 +374,14 @@ The following code example shows how to freeze a row at the top using the `froze ![flutter datagrid shows frozen row at top](images/frozen-pane/flutter-datagrid-frozen-row.gif) -The following code example shows how to freeze a row at the bottom using the `footerFrozenRowsCount.` +The following code example shows how to freeze a row at the bottom using the `footerFrozenRowsCount`: {% tabs %} {% highlight Dart %} +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; + @override Widget build(BuildContext context) { return Scaffold( @@ -439,23 +475,24 @@ The following code example shows how to freeze a row at the bottom using the `fo * SfDataGrid has support to freeze the number of rows from top or bottom. There is no support to freeze a specific row. -N> Header row is frozen by default and works regardless of the `frozenRowsCount` property. +> **Note:** Header row is frozen by default and works regardless of the `frozenRowsCount` property. ## Appearance -The `SfDataGrid` allows customizing the appearance of the freeze pane through the [SfDataGridTheme.SfDataGridThemeData](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData-class.html) property. The DataGrid should be wrapped inside the `SfDataGridTheme.` +The `SfDataGrid` allows customizing the appearance of frozen panes through the [SfDataGridThemeData](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData-class.html) property. The DataGrid should be wrapped inside the [SfDataGridTheme](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridTheme-class.html) widget. -The `SfDataGridThemeData` and `SfDataGridTheme` classes are available in the [syncfusion_flutter_core](https://pub.dev/packages/syncfusion_flutter_core) package. So, import the following file. +The `SfDataGridThemeData` and `SfDataGridTheme` classes are available in the [syncfusion_flutter_core](https://pub.dev/packages/syncfusion_flutter_core) package. Import the required packages: {% tabs %} {% highlight Dart %} import 'package:syncfusion_flutter_core/theme.dart'; +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; {% endhighlight %} {% endtabs %} -The frozen line will be shown only the [SfDataGridThemeData.frozenPaneElevation](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/frozenPaneElevation.html) property to 0. The freeze pane line and freeze pane width can be changed by [frozenPaneLineColor](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/frozenPaneLineColor.html) and [frozenPaneLineWidth](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/frozenPaneLineWidth.html). +The frozen pane line will be shown only when the [frozenPaneElevation](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/frozenPaneElevation.html) property is set to 0. The frozen pane line color and width can be customized using the [frozenPaneLineColor](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/frozenPaneLineColor.html) and [frozenPaneLineWidth](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/frozenPaneLineWidth.html) properties. {% tabs %} {% highlight Dart %} @@ -466,12 +503,13 @@ import 'package:syncfusion_flutter_datagrid/datagrid.dart'; @override Widget build(BuildContext context) { return Scaffold( - body: SfDataGridTheme( - data: SfDataGridThemeData( + body: SfDataGridTheme( + data: SfDataGridThemeData( frozenPaneElevation: 0.0, frozenPaneLineColor: Colors.red, - frozenPaneLineWidth: 1.5), - child: SfDataGrid( + frozenPaneLineWidth: 1.5, + ), + child: SfDataGrid( source: _orderDataGridSource, frozenRowsCount: 1, footerFrozenRowsCount: 1, @@ -479,87 +517,83 @@ import 'package:syncfusion_flutter_datagrid/datagrid.dart'; footerFrozenColumnsCount: 1, columns: [ GridColumn( - columnName: 'id', - label: Container( - alignment: Alignment.centerRight, - padding: EdgeInsets.symmetric(horizontal: 16.0), - child: Text( - 'ID', - overflow: TextOverflow.ellipsis, - ))), + columnName: 'id', + label: Container( + alignment: Alignment.centerRight, + padding: EdgeInsets.symmetric(horizontal: 16.0), + child: Text('ID', overflow: TextOverflow.ellipsis), + ), + ), GridColumn( - columnName: 'productId', - label: Container( - padding: EdgeInsets.symmetric(horizontal: 16.0), - alignment: Alignment.centerRight, - child: Text( - 'Product ID', - overflow: TextOverflow.ellipsis, - ))), + columnName: 'productId', + label: Container( + padding: EdgeInsets.symmetric(horizontal: 16.0), + alignment: Alignment.centerRight, + child: Text('Product ID', overflow: TextOverflow.ellipsis), + ), + ), GridColumn( - columnName: 'name', - label: Container( - padding: EdgeInsets.symmetric(horizontal: 16.0), - alignment: Alignment.centerLeft, - child: Text( - 'Customer Name', - overflow: TextOverflow.ellipsis, - ))), + columnName: 'name', + label: Container( + padding: EdgeInsets.symmetric(horizontal: 16.0), + alignment: Alignment.centerLeft, + child: Text('Customer Name', overflow: TextOverflow.ellipsis), + ), + ), GridColumn( - columnName: 'product', - label: Container( - padding: EdgeInsets.symmetric(horizontal: 16.0), - alignment: Alignment.centerLeft, - child: Text( - 'Product', - overflow: TextOverflow.ellipsis, - ))), + columnName: 'product', + label: Container( + padding: EdgeInsets.symmetric(horizontal: 16.0), + alignment: Alignment.centerLeft, + child: Text('Product', overflow: TextOverflow.ellipsis), + ), + ), GridColumn( - columnName: 'orderDate', - label: Container( - padding: EdgeInsets.symmetric(horizontal: 16.0), - alignment: Alignment.center, - child: Text( - 'Order Date', - overflow: TextOverflow.ellipsis, - ))), + columnName: 'orderDate', + label: Container( + padding: EdgeInsets.symmetric(horizontal: 16.0), + alignment: Alignment.center, + child: Text('Order Date', overflow: TextOverflow.ellipsis), + ), + ), GridColumn( - columnName: 'quantity', - label: Container( - padding: EdgeInsets.symmetric(horizontal: 16.0), - alignment: Alignment.centerRight, - child: Text( - 'Quantity', - overflow: TextOverflow.ellipsis, - ))), + columnName: 'quantity', + label: Container( + padding: EdgeInsets.symmetric(horizontal: 16.0), + alignment: Alignment.centerRight, + child: Text('Quantity', overflow: TextOverflow.ellipsis), + ), + ), GridColumn( - columnName: 'city', - label: Container( - padding: EdgeInsets.symmetric(horizontal: 16.0), - alignment: Alignment.centerLeft, - child: Text( - 'City', - overflow: TextOverflow.ellipsis, - ))), + columnName: 'city', + label: Container( + padding: EdgeInsets.symmetric(horizontal: 16.0), + alignment: Alignment.centerLeft, + child: Text('City', overflow: TextOverflow.ellipsis), + ), + ), GridColumn( - columnName: 'unitPrice', - label: Container( - padding: EdgeInsets.symmetric(horizontal: 16.0), - alignment: Alignment.centerRight, - child: Text( - 'Unit Price', - overflow: TextOverflow.ellipsis, - ))) - ]), - )); + columnName: 'unitPrice', + label: Container( + padding: EdgeInsets.symmetric(horizontal: 16.0), + alignment: Alignment.centerRight, + child: Text('Unit Price', overflow: TextOverflow.ellipsis), + ), + ), + ], + ), + ), + ); } {% endhighlight %} {% endtabs %} -![flutter datagrid shows freeze pane customization](images/frozen-pane/flutter-datagrid-frozen-pane-customization.png) +![flutter datagrid shows frozen pane customization](images/frozen-pane/flutter-datagrid-frozen-pane-customization.png) -The `SfDataGrid` allows customizing the appearance of the freeze pane elevation by using the `SfDataGridThemeData.frozenPaneElevation`. The default value of frozenPaneElevation is 5.0. +### Customize frozen pane elevation + +The `SfDataGrid` allows customizing the appearance of the frozen pane elevation by using the [frozenPaneElevation](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/frozenPaneElevation.html) property. The default value is 5.0. {% tabs %} {% highlight Dart %} @@ -653,15 +687,19 @@ The `SfDataGrid` allows customizing the appearance of the freeze pane elevation {% endhighlight %} {% endtabs %} -![flutter datagrid shows customization of freeze pane elevation](images/frozen-pane/flutter-datagrid-customized-frozen-elevation.png) +![flutter datagrid shows customization of frozen pane elevation](images/frozen-pane/flutter-datagrid-customized-frozen-elevation.png) -## Hide freeze pane elevation +### Customize frozen pane line appearance -By default, the elevation effect is applied to frozen panes. If you want to hide the freeze pane elevation and show only the frozen pane line, simply set the `SfDataGridThemeData.frozenPaneElevation` property to 0. Customize the appearance of the frozen line by using the `SfDataGridThemeData.frozenPaneLineColor` and `SfDataGridThemeData.frozenPaneLineWidth` properties. +By default, the elevation effect is applied to frozen panes. To hide the elevation and display only the frozen pane line, set the [frozenPaneElevation](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/frozenPaneElevation.html) property to 0. Customize the line appearance using the [frozenPaneLineColor](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/frozenPaneLineColor.html) and [frozenPaneLineWidth](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataGridThemeData/frozenPaneLineWidth.html) properties. {% tabs %} {% highlight Dart %} +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_core/theme.dart'; +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; + @override Widget build(BuildContext context) { return Scaffold( @@ -755,3 +793,8 @@ By default, the elevation effect is applied to frozen panes. If you want to hide {% endtabs %} ![flutter datagrid shows how to hide the frozen pane elevation](images/frozen-pane/flutter-datagrid-hide-frozen-elevation.png) + +> **Note:** +>- **Header row behavior** — The header row is frozen by default and remains frozen regardless of the `frozenRowsCount` property. This ensures the column headers remain visible while scrolling through data. +>- **Interaction with other features** — Frozen panes work seamlessly with other DataGrid features including sorting, filtering, selection, and styling. Frozen rows and columns maintain their visual separation during these operations. +>- **Sample applications** — Refer to the [DataGrid freeze panes sample](https://support.syncfusion.com/kb/article/10748/how-to-add-fixed-header-freeze-panes-in-flutter-datatable-sfdatagrid) in the Syncfusion Flutter Examples repository for a complete working implementation. diff --git a/Flutter/datagrid/getting-started.md b/Flutter/datagrid/getting-started.md index c427f1c86..14fe41c50 100644 --- a/Flutter/datagrid/getting-started.md +++ b/Flutter/datagrid/getting-started.md @@ -9,15 +9,17 @@ documentation: ug # Getting started with Flutter DataGrid (SfDataGrid) -This section explains the steps required to add the DataGrid widget and its features. This section covers only the basic features needed to get started with the Syncfusion® Flutter DataGrid widget. +This section explains the steps required to add the SfDataGrid widget and its features. This section covers only the basic features needed to get started with the Syncfusion® Flutter DataGrid widget. -To get started quickly with Flutter DataGrid, check out this video: +> **Note:** Ensure you have Flutter SDK installed. For detailed setup instructions, refer to the [Getting Started with your first Flutter app](https://docs.flutter.dev/get-started/test-drive#choose-your-ide) documentation. + +To get started quickly with Flutter SfDataGrid, check out this video: -## Add Flutter DataGrid to an application +## Add Flutter SfDataGrid to an application -Create a simple project using the instruction given in the [Getting Started with your first Flutter app](https://docs.flutter.dev/get-started/test-drive#choose-your-ide) documentation. +Create a simple project using the instruction given in the [Getting Started with your first Flutter app](https://docs.flutter.dev/get-started/test-drive#choose-your-ide) documentation. **Add dependency** @@ -31,7 +33,7 @@ Add the Syncfusion® Flutter DataGrid dependency to your `pubspec.yaml` file. {% endhighlight %} -N> Here **xx.x.xx** denotes the current version of the [`Syncfusion® Flutter DataGrid`](https://pub.dev/packages/syncfusion_flutter_datagrid/versions) package. +> **Note:** Here **xx.x.xx** denotes the current version of the [`Syncfusion® Flutter DataGrid`](https://pub.dev/packages/syncfusion_flutter_datagrid/versions) package. Refer to the [pub.dev](https://pub.dev/packages/syncfusion_flutter_datagrid/versions) page to check the latest available version. **Get packages** @@ -55,9 +57,9 @@ Import the following package in your Dart code. {% endhighlight %} {% endtabs %} -## Initialize DataGrid +## Initialize SfDataGrid -Add the SfDataGrid widget as a child of any widget. The [SfDataGrid](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid-class.html) requires the [source](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/source.html) and [columns](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/columns.html) properties. Find more details on these properties in further topics. +Add the [SfDataGrid](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid-class.html) widget as a child of any widget. The `SfDataGrid` widget requires the [source](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/source.html) and [columns](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/columns.html) properties. The `source` property is required to provide the data to display, and `columns` is required to define the grid structure. Find more details on these properties in further topics. {% tabs %} {% highlight Dart %} @@ -119,9 +121,11 @@ Add the SfDataGrid widget as a child of any widget. The [SfDataGrid](https://pub {% endhighlight %} {% endtabs %} -## Creating Data for an Application +## Creating data for an application + +The `SfDataGrid` requires data to display. Create a data model class and populate it with sample data as shown in the following code example. -The `SfDataGrid` requires data to display. Create a simple data source for the `SfDataGrid` as shown in the following code example. +**Create the Employee model class:** {% tabs %} {% highlight Dart %} @@ -137,7 +141,9 @@ class Employee { {% endhighlight %} {% endtabs %} -Create the collection of Employee data with the required number of data objects. Here, the `getEmployeeData` method which is used to populate the data objects is initialized in `initState()`. +**Create sample employee collection:** + +Create a collection of `Employee` objects in your StatefulWidget. The following code example shows how to initialize the employee data collection in `initState()` method. You will use this data source in the next step. {% tabs %} {% highlight Dart %} @@ -171,15 +177,15 @@ List getEmployeeData() { {% endhighlight %} {% endtabs %} -## Creating DataSource for DataGrid +## Creating data source for SfDataGrid -[DataGridSource](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource-class.html) is used to obtain the row data for the `SfDataGrid`. So, create the DataSource from the DataGridSource and override the following APIs in it, +[DataGridSource](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource-class.html) is used to obtain the row data for the `SfDataGrid`. Create a custom `DataGridSource` by extending `DataGridSource` and override the following required properties: -* **`rows`** - Fetches the rows available for data population. Also, it is used to fetch the corresponding data object to process the selection. This contains the collection of the `DataGridRow` where each row contains the collection of the `DataGridCell`. Each cell should have the cell value in the `value` property. The `value` is used to perform the sorting for columns. +* **`rows`** - Returns a list of [DataGridRow](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridRow-class.html) objects. Each `DataGridRow` contains a collection of [DataGridCell](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridCell-class.html) objects with cell values. The cell `value` property is used for sorting and selection operations. -* **`buildRow`** - Fetches the widget for each cell with `DataGridRowAdapter`. +* **`buildRow`** - Returns a [DataGridRowAdapter](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridRowAdapter-class.html) that builds the widget for each cell in the row. -`DataGridSource` objects are expected to be long-lived, not recreated with each build. +> **Note:** `DataGridSource` objects are expected to be long-lived, not recreated with each build. Initialize the `DataGridSource` once in the `initState()` method and reuse it. {% tabs %} {% highlight Dart %} @@ -224,7 +230,9 @@ class EmployeeDataSource extends DataGridSource { {% endhighlight %} {% endtabs %} -Create an instance of the `DataGridSource` and set this object to the `source` property of the `SfDataGrid`. +**Use the data source in SfDataGrid:** + +Set the initialized `DataGridSource` to the `source` property of the `SfDataGrid` widget in the `build()` method. {% tabs %} {% highlight Dart %} @@ -234,20 +242,23 @@ late EmployeeDataSource _employeeDataSource; @override Widget build(BuildContext context) { return Scaffold( - body: SfDataGrid( + body: SfDataGrid( source: _employeeDataSource, - )); + columns: [ + // Define columns here + ], + ), + ); } {% endhighlight %} {% endtabs %} ->**NOTE** - You can download the demo application from [GitHub](https://github.com/SyncfusionExamples/getting-started-with-flutter-datagrid). +> **Note:** You can download the demo application from [GitHub](https://github.com/SyncfusionExamples/getting-started-with-flutter-datagrid). ## Defining columns -The `SfDataGrid` supports adding any widget in a column using the `GridColumn` property. Add the column collection to the `columns` property. +The `SfDataGrid` supports adding any widget in a column using the [GridColumn](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn-class.html) widget. Add the column collection to the `columns` property. Each `GridColumn` requires a `columnName` that matches the cell names in your data source and a `label` widget to display the column header. {% tabs %} {% highlight Dart %} @@ -302,144 +313,169 @@ The `SfDataGrid` supports adding any widget in a column using the `GridColumn` p ## Selection -The `SfDataGrid` allows you to select one or more rows. The [selectionMode](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/selectionMode.html) property can be set to specify whether the user can select a single row or multiple rows. +The `SfDataGrid` allows you to select one or more rows. Use the [selectionMode](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/selectionMode.html) property to specify the selection behavior: single row or multiple rows. + +**Enable row selection:** {% tabs %} {% highlight Dart %} - @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, - ) - ) +@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: '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: '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, - ) - ) + ), + GridColumn( + columnName: 'salary', + label: Container( + padding: EdgeInsets.symmetric(horizontal: 16.0), + alignment: Alignment.centerRight, + child: Text( + 'Salary', + overflow: TextOverflow.ellipsis, + ), ), - ], - selectionMode: SelectionMode.multiple, - ) - ); - } + ), + ], + selectionMode: SelectionMode.multiple, + ), + ); +} {% endhighlight %} {% endtabs %} ![flutter datagrid shows rows with selection](images/getting-started/flutter-datagrid-selection.png) -The information about the rows that are selected can be retrieved using the [selectedIndex](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/selectedIndex.html), [selectedRow](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/selectedRow.html) and [selectedRows](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/selectedRows.html) properties in [DataGridController](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController-class.html). You need to initialize the `DataGridController` object to the [controller](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/controller.html) property of `SfDataGrid.` +**Retrieve selection information:** + +You can retrieve information about the selected rows using the [DataGridController](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController-class.html). Initialize a `DataGridController` and assign it to the [controller](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/controller.html) property of `SfDataGrid` to access selection properties: -`DataGridController` objects are expected to be long-lived, not recreated with each build. +* [selectedIndex](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/selectedIndex.html) - Gets the index of the selected row +* [selectedRow](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/selectedRow.html) - Gets the currently selected row +* [selectedRows](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/selectedRows.html) - Gets all selected rows + +> **Note:** `DataGridController` objects are expected to be long-lived, not recreated with each build. Initialize the `DataGridController` once in your State class and reuse it. {% tabs %} {% highlight Dart %} - final DataGridController _controller = DataGridController(); +final DataGridController _controller = DataGridController(); - @override - Widget build(BuildContext context) { - return Scaffold( - body: Column(children: [ - TextButton( - child: Text('Get Selection Information'), +@override +Widget build(BuildContext context) { + return Scaffold( + body: Column( + children: [ + TextButton( onPressed: () { int selectedIndex = _controller.selectedIndex; - DataGridRow selectedRow = _controller.selectedRow!; + DataGridRow? selectedRow = _controller.selectedRow; List selectedRows = _controller.selectedRows; - print(selectedIndex); - print(selectedRow); - print(selectedRows); - }), - Expanded( + + if (selectedRow != null) { + debugPrint('Selected Index: $selectedIndex'); + debugPrint('Selected Row: $selectedRow'); + debugPrint('All Selected Rows: $selectedRows'); + } else { + debugPrint('No row selected'); + } + }, + child: const Text('Get Selection Information'), + ), + Expanded( child: SfDataGrid( - source: _employeeDataSource, - columns: [ - GridColumn( - columnName: 'id', - label: Container( - padding: EdgeInsets.symmetric(horizontal: 16.0), + source: _employeeDataSource, + columns: [ + GridColumn( + columnName: 'id', + label: Container( + padding: const EdgeInsets.symmetric(horizontal: 16.0), alignment: Alignment.centerRight, - child: Text( + child: const Text( 'ID', overflow: TextOverflow.ellipsis, - ))), - GridColumn( - columnName: 'name', - label: Container( - padding: EdgeInsets.symmetric(horizontal: 16.0), + ), + ), + ), + GridColumn( + columnName: 'name', + label: Container( + padding: const EdgeInsets.symmetric(horizontal: 16.0), alignment: Alignment.centerLeft, - child: Text( + child: const Text( 'Name', overflow: TextOverflow.ellipsis, - ))), - GridColumn( - columnName: 'designation', - label: Container( - padding: EdgeInsets.symmetric(horizontal: 16.0), + ), + ), + ), + GridColumn( + columnName: 'designation', + label: Container( + padding: const EdgeInsets.symmetric(horizontal: 16.0), alignment: Alignment.centerLeft, - child: Text( + child: const Text( 'Designation', overflow: TextOverflow.ellipsis, - ))), - GridColumn( - columnName: 'salary', - label: Container( - padding: EdgeInsets.symmetric(horizontal: 16.0), + ), + ), + ), + GridColumn( + columnName: 'salary', + label: Container( + padding: const EdgeInsets.symmetric(horizontal: 16.0), alignment: Alignment.centerRight, - child: Text( + child: const Text( 'Salary', overflow: TextOverflow.ellipsis, - ))), - ], - controller: _controller, - selectionMode: SelectionMode.multiple, - )) - ])); - } + ), + ), + ), + ], + controller: _controller, + selectionMode: SelectionMode.multiple, + ), + ), + ], + ), + ); +} {% endhighlight %} {% endtabs %} ->**NOTE** - `SfDataGrid` supports selection via keyboard interaction for the Web and Desktop platform when `selectionMode` is not `none`. +> **Note:** `SfDataGrid` supports selection via keyboard interaction for the Web and Desktop platform when `selectionMode` is not `none`. diff --git a/Flutter/datagrid/grouping.md b/Flutter/datagrid/grouping.md index 6fc4258ac..f993154e0 100644 --- a/Flutter/datagrid/grouping.md +++ b/Flutter/datagrid/grouping.md @@ -1,7 +1,7 @@ --- layout: post title: Grouping in Flutter DataGrid | DataTable | Syncfusion -description: Learn all about how to perform grouping and multi-grouping to the data source through column in the Syncfusion Flutter DataGrid (SfDataGrid) widget and more here. +description: Learn all about grouping and multi-grouping data through columns in the Syncfusion Flutter DataGrid (SfDataGrid) widget and more. platform: flutter control: SfDataGrid documentation: ug @@ -13,6 +13,8 @@ Grouping in a DataGrid involves organizing and categorizing data based on specif By default, the DataGrid doesn't show the group's caption summary value. To display the caption summary value, you need to override the [DataGridSource.buildGroupCaptionCellWidget](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/buildGroupCaptionCellWidget.html) method. This method receives the caption summary value as a parameter, allowing you to return the necessary widget containing the summary value. +> **Note:** Ensure that you have a populated `DataGridSource` with data rows and columns configured. For custom grouping scenarios, you may need the `collection` package for utility methods like `firstWhereOrNull()`. + ## Programmatic grouping ### Add column group @@ -24,11 +26,14 @@ The `ColumnGroup` object consists of the following properties: * `name`: The column name of the `GridColumn` to be grouped. * `sortGroupRows`: Determines whether to group the column with ascending sorting or not. -The following code demonstrates how to apply grouping to a column +The following code demonstrates how to apply grouping to a column: {% tabs %} {% highlight Dart %} +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; + class SfDataGridDemoState extends State { List employees = []; late EmployeeDataSource employeeDataSource; @@ -55,8 +60,7 @@ class SfDataGridDemoState extends State { label: Container( padding: EdgeInsets.all(8), alignment: Alignment.center, - child: Text( - 'ID'))), + child: Text('ID'))), GridColumn( columnName: 'Name', label: Container( @@ -129,28 +133,25 @@ class EmployeeDataSource extends DataGridSource { ### Remove column group -To disable column grouping for a particular column, remove that `ColumnGroup` instance using the `DataGridSource.removeColumnGroup`` method. +To disable column grouping for a particular column, remove that `ColumnGroup` instance using the [DataGridSource.removeColumnGroup](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/removeColumnGroup.html) method. {% tabs %} {% highlight Dart %} - @override - void initState() { - super.initState(); - employees = getEmployeeData(); - employeeDataSource = EmployeeDataSource(employeeData: employees); - employeeDataSource - .addColumnGroup(ColumnGroup(name: 'Designation', sortGroupRows: true)); - employeeDataSource - .addColumnGroup(ColumnGroup(name: 'Salary', sortGroupRows: false)); - } +import 'package:collection/collection.dart'; +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; + + List employees = []; + late EmployeeDataSource employeeDataSource; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Syncfusion Flutter DataGrid')), - body: Column(children: [ - ElevatedButton( + body: Column( + children: [ + ElevatedButton( onPressed: () { setState(() {}); ColumnGroup? group = employeeDataSource.groupedColumns @@ -159,39 +160,50 @@ To disable column grouping for a particular column, remove that `ColumnGroup` in employeeDataSource.removeColumnGroup(group); } }, - child: Text('Remove Salary Column Group')), - Expanded( + child: Text('Remove Salary Column Group'), + ), + Expanded( child: SfDataGrid( - source: employeeDataSource, - allowExpandCollapseGroup: true, - columns: [ - GridColumn( + source: employeeDataSource, + allowExpandCollapseGroup: true, + columns: [ + GridColumn( columnName: 'ID', label: Container( - padding: EdgeInsets.all(8), - alignment: Alignment.center, - child: Text('ID'))), - GridColumn( + padding: EdgeInsets.all(8), + alignment: Alignment.center, + child: Text('ID'), + ), + ), + GridColumn( columnName: 'Name', label: Container( - padding: EdgeInsets.all(8), - alignment: Alignment.center, - child: Text('Name'))), - GridColumn( + padding: EdgeInsets.all(8), + alignment: Alignment.center, + child: Text('Name'), + ), + ), + GridColumn( columnName: 'Designation', label: Container( - padding: EdgeInsets.all(8), - alignment: Alignment.center, - child: Text('Designation', - overflow: TextOverflow.ellipsis))), - GridColumn( + padding: EdgeInsets.all(8), + alignment: Alignment.center, + child: Text('Designation', overflow: TextOverflow.ellipsis), + ), + ), + GridColumn( columnName: 'Salary', label: Container( - padding: EdgeInsets.all(8), - alignment: Alignment.center, - child: Text('Salary'))), - ])), - ]), + padding: EdgeInsets.all(8), + alignment: Alignment.center, + child: Text('Salary'), + ), + ), + ], + ), + ), + ], + ), ); } @@ -205,51 +217,87 @@ To clear all the column groups, simply call the [DataGridSource.clearColumnGroup {% tabs %} {% highlight Dart %} +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; + +class SfDataGridDemoState extends State { + List employees = []; + late EmployeeDataSource employeeDataSource; + + @override + void initState() { + super.initState(); + employees = getEmployeeData(); + employeeDataSource = EmployeeDataSource(employeeData: employees); + employeeDataSource.addColumnGroup( + ColumnGroup(name: 'Designation', sortGroupRows: true), + ); + employeeDataSource.addColumnGroup( + ColumnGroup(name: 'Salary', sortGroupRows: false), + ); + } + @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Syncfusion Flutter DataGrid')), - body: Column(children: [ - ElevatedButton( + body: Column( + children: [ + ElevatedButton( onPressed: () { setState(() {}); employeeDataSource.clearColumnGroups(); }, - child: Text('Clear all column groups')), - Expanded( + child: const Text('Clear all column groups'), + ), + Expanded( child: SfDataGrid( - source: employeeDataSource, - allowExpandCollapseGroup: true, - columns: [ - GridColumn( + source: employeeDataSource, + allowExpandCollapseGroup: true, + columns: [ + GridColumn( columnName: 'ID', label: Container( - padding: EdgeInsets.all(8), - alignment: Alignment.center, - child: Text('ID'))), - GridColumn( + padding: EdgeInsets.all(8), + alignment: Alignment.center, + child: const Text('ID'), + ), + ), + GridColumn( columnName: 'Name', label: Container( - padding: EdgeInsets.all(8), - alignment: Alignment.center, - child: Text('Name'))), - GridColumn( + padding: EdgeInsets.all(8), + alignment: Alignment.center, + child: const Text('Name'), + ), + ), + GridColumn( columnName: 'Designation', label: Container( - padding: EdgeInsets.all(8), - alignment: Alignment.center, - child: Text('Designation', - overflow: TextOverflow.ellipsis))), - GridColumn( + padding: EdgeInsets.all(8), + alignment: Alignment.center, + child: const Text( + 'Designation', + overflow: TextOverflow.ellipsis, + ), + ), + ), + GridColumn( columnName: 'Salary', label: Container( - padding: EdgeInsets.all(8), - alignment: Alignment.center, - child: Text('Salary'))), - ])), - ]), + padding: EdgeInsets.all(8), + alignment: Alignment.center, + child: const Text('Salary'), + ), + ), + ], + ), + ), + ], + ), ); } +} {% endhighlight %} {% endtabs %} @@ -538,20 +586,29 @@ The [SfDataGrid.groupCollapsed](https://pub.dev/documentation/syncfusion_flutter ## Custom grouping -The `SfDataGrid` provides support to group a column using custom logic when standard grouping techniques aren't sufficient for specific requirements. This can be accomplished by overriding the [DataGridSource.performGrouping](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/performGrouping.html) method. +Use custom grouping when you need to group data based on derived or transformed values, such as salary ranges, age groups, or custom categories that don't directly correspond to column values. This approach provides more flexibility than standard column-based grouping. -The `DataGridSource.performGrouping` method is invoked when grouping is applied to the `SfDataGrid`. Within this method, you can implement custom logic to return a `String` based on your specific requirements. +Custom grouping is implemented by overriding the [DataGridSource.performGrouping](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/performGrouping.html) method. This method is invoked when grouping is applied to the `SfDataGrid`, allowing you to implement custom logic and return a `String` representing the group key for each row. {% tabs %} {% highlight Dart %} +import 'package:collection/collection.dart'; +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; +import 'package:flutter/material.dart'; + +class SfDataGridDemoState extends State { + List employees = []; + late EmployeeDataSource employeeDataSource; + @override void initState() { super.initState(); employees = getEmployeeData(); employeeDataSource = EmployeeDataSource(employeeData: employees); - employeeDataSource - .addColumnGroup(ColumnGroup(name: 'Salary', sortGroupRows: true)); + employeeDataSource.addColumnGroup( + ColumnGroup(name: 'Salary', sortGroupRows: true), + ); } @override @@ -559,53 +616,63 @@ The `DataGridSource.performGrouping` method is invoked when grouping is applied return Scaffold( appBar: AppBar(title: const Text('Syncfusion Flutter DataGrid')), body: SfDataGrid( - source: employeeDataSource, - allowExpandCollapseGroup: true, - groupExpanded: (group) { - print('Group expanding: ${group.key}'); - print('Group level: ${group.groupLevel}'); - }, - columns: [ - GridColumn( - columnName: 'ID', - label: Container( - padding: EdgeInsets.all(8), - alignment: Alignment.center, - child: Text('ID'))), - GridColumn( - columnName: 'Name', - label: Container( - padding: EdgeInsets.all(8), - alignment: Alignment.center, - child: Text('Name'))), - GridColumn( - columnName: 'Designation', - label: Container( - padding: EdgeInsets.all(8), - alignment: Alignment.center, - child: - Text('Designation', overflow: TextOverflow.ellipsis))), - GridColumn( - columnName: 'Salary', - label: Container( - padding: EdgeInsets.all(8), - alignment: Alignment.center, - child: Text('Salary'))), - ]), + source: employeeDataSource, + allowExpandCollapseGroup: true, + columns: [ + GridColumn( + columnName: 'ID', + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.center, + child: Text('ID'), + ), + ), + GridColumn( + columnName: 'Name', + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.center, + child: Text('Name'), + ), + ), + GridColumn( + columnName: 'Designation', + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.center, + child: Text('Designation', overflow: TextOverflow.ellipsis), + ), + ), + GridColumn( + columnName: 'Salary', + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.center, + child: Text('Salary'), + ), + ), + ], + ), ); } - +} class EmployeeDataSource extends DataGridSource { EmployeeDataSource({required List employeeData}) { dataGridRows = employeeData - .map((e) => DataGridRow(cells: [ + .map( + (e) => DataGridRow( + cells: [ DataGridCell(columnName: 'ID', value: e.id), DataGridCell(columnName: 'Name', value: e.name), DataGridCell( - columnName: 'Designation', value: e.designation), + columnName: 'Designation', + value: e.designation, + ), DataGridCell(columnName: 'Salary', value: e.salary), - ])) + ], + ), + ) .toList(); } @@ -617,43 +684,50 @@ class EmployeeDataSource extends DataGridSource { @override DataGridRowAdapter buildRow(DataGridRow row) { return DataGridRowAdapter( - cells: row.getCells().map((e) { - return Container( - alignment: Alignment.center, - padding: EdgeInsets.all(8), - child: Text( - e.value.toString(), - ), - ); - }).toList()); + cells: row.getCells().map((e) { + return Container( + alignment: Alignment.center, + padding: EdgeInsets.all(8), + child: Text(e.value.toString()), + ); + }).toList(), + ); } @override Widget? buildGroupCaptionCellWidget( - RowColumnIndex rowColumnIndex, String summaryValue) { + RowColumnIndex rowColumnIndex, + String summaryValue, + ) { return Container( - padding: EdgeInsets.symmetric(horizontal: 12, vertical: 15), - child: Text(summaryValue)); + padding: EdgeInsets.symmetric(horizontal: 12, vertical: 15), + child: Text(summaryValue), + ); } @override String performGrouping(String columnName, DataGridRow row) { if (columnName == 'Salary') { - final double total = row + final DataGridCell? salaryCell = row .getCells() + .whereType>() .firstWhereOrNull( - (DataGridCell cell) => cell.columnName == columnName)! - .value; - if (total > 100000 && total <= 200000) { - return '> 100 K & <= 150 K'; - } else if (total > 90000 && total <= 100000) { - return '> 90 K & <= 100 K'; - } else if (total > 50000 && total <= 90000) { - return '> 50 K & <= 90 K'; - } else if (total > 30000 && total <= 50000) { - return '> 30 K & <= 50 K'; - } else { - return '<= 30 K'; + (DataGridCell cell) => cell.columnName == columnName, + ); + + if (salaryCell != null && salaryCell.value != null) { + final double total = salaryCell.value!; + if (total > 100000 && total <= 200000) { + return '> 100 K & <= 200 K'; + } else if (total > 90000 && total <= 100000) { + return '> 90 K & <= 100 K'; + } else if (total > 50000 && total <= 90000) { + return '> 50 K & <= 90 K'; + } else if (total > 30000 && total <= 50000) { + return '> 30 K & <= 50 K'; + } else { + return '<= 30 K'; + } } } return super.performGrouping(columnName, row); @@ -667,7 +741,9 @@ class EmployeeDataSource extends DataGridSource { ## Enable group expand and collapse -The group expand and collapse functionality can be enabled by setting the [SfDataGrid.allowExpandCollapseGroup](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/allowExpandCollapseGroup.html) property to `true`. The default value of this property is `false.` +The group expand and collapse functionality can be enabled by setting the [SfDataGrid.allowExpandCollapseGroup](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/allowExpandCollapseGroup.html) property to `true`. The default value of this property is `false`. + +When `allowExpandCollapseGroup` is set to `false`, groups are displayed but users cannot expand or collapse them; all groups remain in their default state as determined by the `autoExpandGroups` property. {% tabs %} {% highlight Dart %} @@ -723,7 +799,7 @@ The group expand and collapse functionality can be enabled by setting the [SfDat ## Disable group expanding on the initial loading -By default, the SfDataGrid always expands all the groups. All the groups can be collapsed intially by setting the [SfDataGrid.autoExpandGroups](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/autoExpandGroups.html) property to false. +By default, the SfDataGrid always expands all the groups. All the groups can be collapsed initially by setting the [SfDataGrid.autoExpandGroups](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/autoExpandGroups.html) property to false. {% tabs %} {% highlight Dart %} @@ -771,7 +847,7 @@ By default, the SfDataGrid always expands all the groups. All the groups can be ## Programmatically expand and collapse groups -Expanding and collapsing groups programmatically can be achieved using the following `DataGridController` methods, +Expanding and collapsing groups programmatically can be achieved using the following [DataGridController](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController-class.html) methods: @@ -779,26 +855,126 @@ Expanding and collapsing groups programmatically can be achieved using the follo - - + + - - + + - - + + - - + +
Description
DataGridController.expandAllGroup Expands all the groups in the SfDataGrid expandAllGroupExpands all the groups in the SfDataGrid
DataGridController.collapseAllGroup. Collapses all the groups in the SfDataGrid collapseAllGroupCollapses all the groups in the SfDataGrid
DataGridController.expandGroupsAtLevel. Expands the group based on the group level expandGroupsAtLevelExpands the groups based on the group level
DataGridController.collapseGroupsAtLevel. Collapses the group based on the group level collapseGroupsAtLevelCollapses the groups based on the group level
+The following code example demonstrates how to use these methods: + +{% tabs %} +{% highlight Dart %} + + List _employees = []; + late EmployeeDataSource _employeeDataSource; + final DataGridController _dataGridController = DataGridController(); + + @override + void initState() { + super.initState(); + _employees = getEmployeeData(); + _employeeDataSource = EmployeeDataSource(employeeData: _employees); + _employeeDataSource.addColumnGroup( + ColumnGroup(name: 'Designation', sortGroupRows: true), + ); + _employeeDataSource.addColumnGroup( + ColumnGroup(name: 'Salary', sortGroupRows: false), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Syncfusion Flutter DataGrid')), + body: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + ElevatedButton( + onPressed: () { + _dataGridController.expandAllGroup(); + }, + child: const Text('Expand All'), + ), + ElevatedButton( + onPressed: () { + _dataGridController.collapseAllGroup(); + }, + child: const Text('Collapse All'), + ), + ], + ), + Expanded( + child: SfDataGrid( + controller: _dataGridController, + source: _employeeDataSource, + gridLinesVisibility: GridLinesVisibility.both, + headerGridLinesVisibility: GridLinesVisibility.both, + allowExpandCollapseGroup: true, + columns: [ + GridColumn( + columnName: 'ID', + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.center, + child: Text('ID'), + ), + ), + GridColumn( + columnName: 'Name', + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.center, + child: Text('Name'), + ), + ), + GridColumn( + columnName: 'Designation', + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.center, + child: Text('Designation', overflow: TextOverflow.ellipsis), + ), + ), + GridColumn( + columnName: 'Salary', + label: Container( + padding: EdgeInsets.all(8), + alignment: Alignment.center, + child: Text('Salary'), + ), + ), + ], + ), + ), + ], + ), + ); + } + +{% endhighlight %} +{% endtabs %} + ## Customize the group caption summary row format -The caption summary value is displayed in a caption summary row by the default format `'{ColumnName} : {Key} - {ItemsCount} Items'.` The `{ColumnName}` defines the name of the grouped column, {Key} defines the identical cell value of the group, and `{ItemsCount}` defines the length of the rows in the group. +The caption summary value is displayed in a caption summary row by the default format `'{ColumnName} : {Key} - {ItemsCount} Items'`. The available placeholders for customizing the format are: + +* `{ColumnName}`: The name of the grouped column +* `{Key}`: The identical cell value of the group +* `{ItemsCount}`: The number of rows in the group The format can be customized by using the [SfDataGrid.groupCaptionTitleFormat](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/groupCaptionTitleFormat.html) property. @@ -960,5 +1136,5 @@ The `SfDataGridThemeData` and `SfDataGridTheme` classes are available in the [sy ## Limitations -* The grouping will be refreshed when performing CRUD operations on the [DataGridSource.rows](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/rows.html) and the [SfDataGrid.columns](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/columns.html).` Consequently, this action resets the expand and collapse states of the groups based on the [SfDataGrid.autoExpandGroups](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/autoExpandGroups.html) property. -* To prevent unnecessary grouping refresh, ensure that the `SfDataGrid.columns` property is set as an instance. +* Grouping is refreshed when performing CRUD operations on [DataGridSource.rows](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/rows.html) or [SfDataGrid.columns](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/columns.html). This action resets expand and collapse states of groups based on the [SfDataGrid.autoExpandGroups](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/autoExpandGroups.html) property. To work around this, update the `rows` collection in-place rather than reassigning it completely. +* To prevent unnecessary grouping refresh, ensure that the `SfDataGrid.columns` property is assigned once as a single instance rather than being recreated on each build or state change. diff --git a/Flutter/datagrid/how-to/custom-widget-on-flutterflow.md b/Flutter/datagrid/how-to/custom-widget-on-flutterflow.md index b7fa81d3d..d718330ef 100644 --- a/Flutter/datagrid/how-to/custom-widget-on-flutterflow.md +++ b/Flutter/datagrid/how-to/custom-widget-on-flutterflow.md @@ -11,7 +11,9 @@ documentation: ug ## Overview -[FlutterFlow](https://app.flutterflow.io/dashboard) enables you to create native applications using its graphical interface, reducing the need to write extensive amounts of code. Additionally, it offers the capability to include custom widgets that are not included in the default [FlutterFlow](https://app.flutterflow.io/dashboard) widget collection. This article explains how to incorporate our SfDataGrid widget as a custom widget in [FlutterFlow](https://app.flutterflow.io/dashboard). +[FlutterFlow](https://app.flutterflow.io/dashboard) enables you to create native applications using its graphical interface, reducing the need to write extensive amounts of code. Additionally, it offers the capability to include custom widgets that are not included in the default [FlutterFlow](https://app.flutterflow.io/dashboard) widget collection. This article explains how to incorporate the SfDataGrid widget as a custom widget in FlutterFlow. + +> **Note:** You need an active FlutterFlow account and basic knowledge of Flutter development to follow this guide. Refer to the [SDK version compatibility](https://help.syncfusion.com/flutter/system-requirements#sdk-version-compatibility) to ensure your FlutterFlow's Flutter version is compatible with the Syncfusion Flutter DataGrid package. ### Create a new project @@ -22,54 +24,56 @@ Navigate to the [FlutterFlow dashboard](https://app.flutterflow.io/dashboard) an 1. Navigate to the `Custom Code` section in the left side navigation menu. 2. Click on the `+ Add` button to open a dropdown menu, then select `Widget`. 3. Update the widget name as desired. -4. Click the `View Boilerplate Code` button on the right side, represented by this icon `[]`. -5. A popup will appear with startup code; locate the button labeled ` Copy to Editor` and click on it. -6. Save the widget. +4. Click the `View Boilerplate Code` button on the right side, represented by the code icon (``). +5. A popup will appear with startup code. Locate the button labeled ` Copy to Editor` and click on it to load the boilerplate code into the editor. +6. Click `Save` to save the custom widget. ![Custom Widget](how-to-section-images/custom-widget.png) ### Add DataGrid widget as a dependency 1. Click on `+ Add Dependency`, a text editor will appear. -2. Navigate to [Syncfusion Flutter DataGrid](https://pub.dev/packages/syncfusion_flutter_DataGrid) in [pub.dev](https://pub.dev/) and copy the dependency name and version using the `Copy to Clipboard` option. +2. Navigate to the [Syncfusion Flutter DataGrid package](https://pub.dev/packages/syncfusion_flutter_DataGrid) on pub.dev and copy the dependency name and version using the `Copy to Clipboard` option. ![Version](how-to-section-images/copy-version.png) 3. Paste the copied dependency into the text editor, then click `Refresh` and `Save` it. ->**Note**: The live version of [Syncfusion Flutter DataGrid](https://pub.dev/packages/syncfusion_flutter_DataGrid) has been migrated to the latest version of Flutter SDK. To ensure compatibility, check [FlutterFlow](https://app.flutterflow.io/dashboard)'s current Flutter version and obtain the corresponding version of [Syncfusion Flutter DataGrid](https://pub.dev/packages/syncfusion_flutter_DataGrid) by referring to the [SDK compatibility](https://help.syncfusion.com/flutter/system-requirements#sdk-version-compatibility). +>**Note**: +>- If you need a specific version instead of the latest, remove the caret (^) prefix in the version number. For example, change `^21.3.0` to `21.3.0` to lock to that exact version. +>- The SfDataGrid package depends on the [Syncfusion Flutter Core](https://pub.dev/packages/syncfusion_flutter_core) package. Make sure to add it as a dependency using the same steps above. ![Dependency](how-to-section-images/dependency.png) ->**Note**: If you are using an older version of a dependency instead of the latest one, remove the caret symbol (^) prefix in the version number after pasting the dependency. For example, change `^21.3.0` to `21.3.0`. - ->**Note**: Since [Syncfusion Flutter DataGrid](https://pub.dev/packages/syncfusion_flutter_DataGrid) depends on the [Syncfusion Flutter Core](https://pub.dev/packages/syncfusion_flutter_core) package, make sure to add it as a dependency following the same steps mentioned above. - ### Import the package -1. Navigate to the `Installing` tab on the [Syncfusion Flutter DataGrid](https://pub.dev/packages/syncfusion_flutter_DataGrid) page. Under the `Import it` section, copy the package import statement. +1. Navigate to the **Installing** tab on the [Syncfusion Flutter DataGrid package](https://pub.dev/packages/syncfusion_flutter_DataGrid) page. Under the **Import it** section, copy the package import statement. ![Package](how-to-section-images/copy-package.png) -2. Paste the copied import statement into the code editor and then `Save` it. +2. Paste the copied import statement into the code editor and click `Save`. ![Import](how-to-section-images/import-package-flutterflow.png) ### Add widget code snippet in code editor -1. Navigate to the [Example](https://pub.dev/packages/syncfusion_flutter_DataGrid/example) tab in [Syncfusion Flutter DataGrid](https://pub.dev/packages/syncfusion_flutter_DataGrid) and copy the widget specific codes. +1. Navigate to the **Example** tab in the [Syncfusion Flutter DataGrid package](https://pub.dev/packages/syncfusion_flutter_DataGrid/example) page and copy the widget code example. ![Code](how-to-section-images/code-snippet.png) -2. Paste the copied code sample into the code editor, click `Format Code`, and `Save` it. +2. Paste the copied code into the editor, click `Format Code` to format it to standard style, and then click `Save`. ![Code snippet](how-to-section-images/Adding-code-snippent.png) -### Compiling the codes +### Compiling the code -1. Click the 'Compile Code' button located in the top right corner. -2. If there are no errors, save the process. If errors are present, fix them and compile the code again. Once the code has been successfully compiled, save the process. +1. Click the **Compile Code** button located in the top right corner. +2. Wait for the compilation to complete (typically 2-3 minutes). The status will display at the top of the editor. +3. Once compilation succeeds, a confirmation message will appear. If errors occur, review the error messages, fix the code, and compile again. +4. Click `Save` after successful compilation. ![Compile code](how-to-section-images/compile-code.png) ->**Note**: The compilation progress takes 2 to 3 minutes to complete. +>**Note**: Compilation typically takes 2 to 3 minutes. The editor will display compilation status and any errors encountered during the build process. -### Utilizing the custom widget +### Using the custom widget in your app -1. Navigate to `Widget Palette` located in the left side navigation menu. -2. Click on the `Components` tab. -3. Your custom widget will be under `Custom Code Widgets`. Drag and drop the custom widget to your page. +1. Navigate to **Widget Palette** in the left side navigation menu. +2. Click on the **Components** tab. +3. Locate your custom widget under **Custom Code Widgets**. Drag and drop it onto your page. +4. Configure the SfDataGrid properties and data source as needed. Refer to the [SfDataGrid API documentation](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/) for detailed configuration options. +5. Run your FlutterFlow app to verify the SfDataGrid widget displays correctly. ![Page](how-to-section-images/page.png) diff --git a/Flutter/datagrid/load-more.md b/Flutter/datagrid/load-more.md index 88a02a389..400283a6d 100644 --- a/Flutter/datagrid/load-more.md +++ b/Flutter/datagrid/load-more.md @@ -7,26 +7,49 @@ control: SfDataGrid documentation: ug --- -# Load more in Flutter Datagrid (SfDataGrid) +# Load more in Flutter DataGrid (SfDataGrid) -The datagrid provides support to display an interactive view when the grid reaches its maximum offset while scrolling down. You can use [loadMoreViewBuilder](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/loadMoreViewBuilder.html) builder to display the view at bottom of datagrid. +The SfDataGrid widget provides support to display an interactive view when the grid reaches its maximum offset while scrolling down. You can use the [loadMoreViewBuilder](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/loadMoreViewBuilder.html) property to display a custom view at the bottom of the grid. -You should override the [DataGridSource.handleLoadMoreRows](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/handleLoadMoreRows.html) method to load more rows and then notify the datagrid about the changes. The `DataGridSource.handleLoadMoreRows` can be called to load more rows from this builder by using the [loadMoreRows](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/LoadMoreRows.html) function which is passed as a parameter to `loadMoreViewBuilder`. +To implement load more functionality, override the [DataGridSource.handleLoadMoreRows](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/handleLoadMoreRows.html) method to load additional rows and notify the grid about the changes. The `handleLoadMoreRows` method is automatically called when the user scrolls to the bottom of the grid. Use the [LoadMoreRows](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/LoadMoreRows.html) function, passed as a parameter to `loadMoreViewBuilder`, to trigger row loading. ## Infinite scrolling -Infinite Scrolling is an approach that can be used to load more rows to the datagrid whenever the datagrid reaches the bottom. +Infinite scrolling automatically loads more rows as the user scrolls to the bottom of the grid, creating a seamless continuous data experience. This approach is ideal when you have a large dataset and want to load data progressively without user interaction. -The following example demonstrates infinite scrolling by showing the circular progress indicator until the rows are loaded when the datagrid reaches the bottom, +The following example demonstrates infinite scrolling by displaying a circular progress indicator while rows are being loaded: {% tabs %} {% highlight Dart %} +import 'package:flutter/material.dart'; import 'package:syncfusion_flutter_datagrid/datagrid.dart'; +import 'dart:math'; + +class Employee { + Employee(this.id, this.name, this.designation, this.salary); + + final int id; + final String name; + final String designation; + final int salary; +} + +class MyHomePageState extends State { + List _employees = []; + late EmployeeDataSource _employeeDataSource; + + @override + void initState() { + super.initState(); + _employees = getEmployeeData(); + _employeeDataSource = EmployeeDataSource(employeeData: _employees); + } @override Widget build(BuildContext context) { - return SfDataGrid( + return Scaffold( + body: SfDataGrid( source: _employeeDataSource, loadMoreViewBuilder: (BuildContext context, LoadMoreRows loadMoreRows) { Future loadRows() async { @@ -38,69 +61,92 @@ import 'package:syncfusion_flutter_datagrid/datagrid.dart'; } return FutureBuilder( - initialData: 'loading', - future: loadRows(), - builder: (context, snapShot) { - if (snapShot.data == 'loading') { - return Container( - height: 60.0, - width: double.infinity, - decoration: BoxDecoration( - color: Colors.white, - border: BorderDirectional( - top: BorderSide( - width: 1.0, - color: Color.fromRGBO(0, 0, 0, 0.26)))), - alignment: Alignment.center, - child: CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation(Colors.deepPurple))); - } else { - return SizedBox.fromSize(size: Size.zero); - } - }); + initialData: 'loading', + future: loadRows(), + builder: (context, snapShot) { + if (snapShot.data == 'loading') { + return Container( + height: 60.0, + width: double.infinity, + decoration: BoxDecoration( + color: Colors.white, + border: BorderDirectional( + top: BorderSide( + width: 1.0, + color: Color.fromRGBO(0, 0, 0, 0.26), + ), + ), + ), + alignment: Alignment.center, + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(Colors.deepPurple), + ), + ); + } else { + return SizedBox.fromSize(size: Size.zero); + } + }, + ); }, columns: [ GridColumn( - columnName: 'id', - label: Container( - padding: EdgeInsets.symmetric(horizontal: 16.0), - alignment: Alignment.centerRight, - child: Text( - 'ID', - overflow: TextOverflow.ellipsis, - ))), + 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, - ))), + 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, - ))), + 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, - ))) - ]); + columnName: 'salary', + label: Container( + padding: EdgeInsets.symmetric(horizontal: 16.0), + alignment: Alignment.centerRight, + child: Text('Salary', overflow: TextOverflow.ellipsis), + ), + ), + ], + ), + ); } +} + +List getEmployeeData() { + return [ + Employee(10001, 'James', 'Project Lead', 20000), + Employee(10002, 'Kathryn', 'Manager', 30000), + Employee(10003, 'Lara', 'Developer', 15000), + Employee(10004, 'Michael', 'Designer', 15000), + Employee(10005, 'Martin', 'Developer', 15000), + Employee(10006, 'Newberry', 'Developer', 15000), + Employee(10007, 'Balnc', 'Developer', 15000), + Employee(10008, 'Perry', 'Developer', 15000), + Employee(10009, 'Gable', 'Developer', 15000), + Employee(10010, 'Grimes', 'Developer', 15000), + ]; +} class EmployeeDataSource extends DataGridSource { - EmployeeDataSource() { + static final List _employees = []; + + EmployeeDataSource({required List employeeData}) { + _employees.addAll(employeeData); buildDataGridRows(); } @@ -112,23 +158,27 @@ class EmployeeDataSource extends DataGridSource { @override DataGridRowAdapter? buildRow(DataGridRow row) { return DataGridRowAdapter( - cells: row.getCells().map((dataGridCell) { - return Container( - alignment: (dataGridCell.columnName == 'id' || + cells: row.getCells().map((dataGridCell) { + return Container( + alignment: + (dataGridCell.columnName == 'id' || dataGridCell.columnName == 'salary') ? Alignment.centerRight : Alignment.centerLeft, - padding: EdgeInsets.symmetric(horizontal: 16.0), + padding: const EdgeInsets.symmetric(horizontal: 16.0), child: Text( dataGridCell.value.toString(), overflow: TextOverflow.ellipsis, - )); - }).toList()); + ), + ); + }).toList(), + ); } @override Future handleLoadMoreRows() async { - await Future.delayed(Duration(seconds: 5)); + // Simulate network delay for loading data + await Future.delayed(const Duration(seconds: 2)); _addMoreRows(_employees, 15); buildDataGridRows(); notifyListeners(); @@ -136,28 +186,38 @@ class EmployeeDataSource extends DataGridSource { void buildDataGridRows() { dataGridRows = _employees - .map((dataGridRow) => DataGridRow(cells: [ + .map( + (dataGridRow) => DataGridRow( + cells: [ DataGridCell(columnName: 'id', value: dataGridRow.id), DataGridCell(columnName: 'name', value: dataGridRow.name), DataGridCell( - columnName: 'designation', value: dataGridRow.designation), + columnName: 'designation', + value: dataGridRow.designation, + ), DataGridCell( - columnName: 'salary', value: dataGridRow.salary), - ])) + columnName: 'salary', + value: dataGridRow.salary, + ), + ], + ), + ) .toList(); } void _addMoreRows(List employees, int count) { - final Random _random = Random(); + final Random random = Random(); final startIndex = employees.isNotEmpty ? employees.length : 0, endIndex = startIndex + count; for (int i = startIndex; i < endIndex; i++) { - employees.add(Employee( - 1000 + i, - _names[_random.nextInt(_names.length - 1)], - _designation[_random.nextInt(_designation.length - 1)], - 10000 + _random.nextInt(10000), - )); + employees.add( + Employee( + 1000 + i, + _names[random.nextInt(_names.length)], + _designation[random.nextInt(_designation.length)], + 10000 + random.nextInt(10000), + ), + ); } } @@ -176,7 +236,7 @@ class EmployeeDataSource extends DataGridSource { 'Riscu', 'Seves', 'Vaffe', - 'Alfki' + 'Alfki', ]; final List _designation = [ @@ -185,139 +245,188 @@ class EmployeeDataSource extends DataGridSource { 'Manager', 'Designer', 'System Analyst', - 'CEO' + 'CEO', ]; } {% endhighlight %} {% endtabs %} -**NOTE** - Download demo application from [GitHub](https://github.com/SyncfusionExamples/how-to-do-the-infinite-scrolling-in-syncfusion-flutter-datatable). +> **Note:** Download the demo application from [GitHub](https://github.com/SyncfusionExamples/how-to-do-the-infinite-scrolling-in-syncfusion-flutter-datatable). ![flutter datagrid shows load more with infinite scrolling behavior](images/load-more/flutter-datagrid-load-more-infinite-scrolling.gif) ## Load more button -Showing load more button is an approach that can be used to load more rows to the datagrid by tapping a button that you load from the `SfDataGrid.loadMoreViewBuilder` builder. The button will be loaded when vertical scrolling is reached at the end of the datagrid. +You can display a load more button that the user can tap to load additional rows on demand. This approach gives users explicit control over data loading rather than automatic loading as with infinite scrolling. -The following example demonstrates how to show the button when vertical scrolling is reached at the end of the datagrid and display the circular indicator until the rows are loaded when you tap that button. In the onPressed flat button callback, you can call the `loadMoreRows` function to add more rows, +The following example demonstrates how to display a button when vertical scrolling reaches the end of the grid, show a loading indicator while rows are being fetched, and load more rows when the button is tapped by calling the `loadMoreRows` function: {% tabs %} {% highlight Dart %} +import 'package:flutter/material.dart'; import 'package:syncfusion_flutter_datagrid/datagrid.dart'; +import 'dart:math'; + +class Employee { + Employee(this.id, this.name, this.designation, this.salary); + + final int id; + final String name; + final String designation; + final int salary; +} + +class MyHomePageState extends State { + List _employees = []; + late EmployeeDataSource _employeeDataSource; + + @override + void initState() { + super.initState(); + _employees = getEmployeeData(); + _employeeDataSource = EmployeeDataSource(employeeData: _employees); + } @override Widget build(BuildContext context) { - return SfDataGrid( + return Scaffold( + body: SfDataGrid( source: _employeeDataSource, loadMoreViewBuilder: (BuildContext context, LoadMoreRows loadMoreRows) { bool showIndicator = false; return StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - if (showIndicator) { - return Container( + builder: (BuildContext context, StateSetter setState) { + if (showIndicator) { + return Container( height: 60.0, width: double.infinity, alignment: Alignment.center, decoration: BoxDecoration( - color: Colors.white, - border: BorderDirectional( - top: BorderSide( - width: 1.0, color: Color.fromRGBO(0, 0, 0, 0.26)))), - child: CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation(Colors.deepPurple))); - } else { - return Container( + color: Colors.white, + border: const BorderDirectional( + top: BorderSide( + width: 1.0, + color: Color.fromRGBO(0, 0, 0, 0.26), + ), + ), + ), + child: const CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(Colors.deepPurple), + ), + ); + } else { + return Container( height: 60.0, width: double.infinity, alignment: Alignment.center, decoration: BoxDecoration( - color: Colors.white, - border: BorderDirectional( - top: BorderSide( - width: 1.0, color: Color.fromRGBO(0, 0, 0, 0.26)))), - child: Container( - height: 36.0, - width: 142.0, - child: TextButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all(Colors.purple)), - child: Text('LOAD MORE', - style: TextStyle(color: Colors.white)), - onPressed: () async { - // To avoid the "Error: setState() called after dispose():" - // while scrolling the datagrid vertically and displaying the - // load more view, current load more view is checked whether - // loaded widget is mounted or not. - if (context is StatefulElement && - context.state.mounted) { - setState(() { - showIndicator = true; - }); - } - // Call the loadMoreRows function to call the - // DataGridSource.handleLoadMoreRows method. So, additional - // rows can be added from handleLoadMoreRows method. - await loadMoreRows(); - // To avoid the "Error: setState() called after dispose():" - // while scrolling the datagrid vertically and displaying the - // load more view, current load more view is checked whether - // loaded widget is mounted or not. - if (context is StatefulElement && - context.state.mounted) { - setState(() { - showIndicator = false; - }); - } - }))); - } - }); + color: Colors.white, + border: const BorderDirectional( + top: BorderSide( + width: 1.0, + color: Color.fromRGBO(0, 0, 0, 0.26), + ), + ), + ), + child: SizedBox( + height: 36.0, + width: 142.0, + child: TextButton( + style: ButtonStyle( + backgroundColor: WidgetStateProperty.all(Colors.purple), + ), + child: const Text( + 'LOAD MORE', + style: TextStyle(color: Colors.white), + ), + onPressed: () async { + // Check if the widget is still mounted to avoid + // "setState() called after dispose()" errors + if (context is StatefulElement && + context.state.mounted) { + setState(() { + showIndicator = true; + }); + } + // Call the loadMoreRows function to trigger + // DataGridSource.handleLoadMoreRows method + await loadMoreRows(); + // Reset the indicator state when loading completes + if (context is StatefulElement && + context.state.mounted) { + setState(() { + showIndicator = false; + }); + } + }, + ), + ), + ); + } + }, + ); }, columns: [ GridColumn( - columnName: 'id', - label: Container( - padding: EdgeInsets.symmetric(horizontal: 16.0), - alignment: Alignment.centerRight, - child: Text( - 'ID', - overflow: TextOverflow.ellipsis, - ))), + 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, - ))), + 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, - ))), + 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, - ))) - ]); + columnName: 'salary', + label: Container( + padding: EdgeInsets.symmetric(horizontal: 16.0), + alignment: Alignment.centerRight, + child: Text('Salary', overflow: TextOverflow.ellipsis), + ), + ), + ], + ), + ); } +} + +List getEmployeeData() { + return [ + Employee(10001, 'James', 'Project Lead', 20000), + Employee(10002, 'Kathryn', 'Manager', 30000), + Employee(10003, 'Lara', 'Developer', 15000), + Employee(10004, 'Michael', 'Designer', 15000), + Employee(10005, 'Martin', 'Developer', 15000), + Employee(10006, 'Newberry', 'Developer', 15000), + Employee(10007, 'Balnc', 'Developer', 15000), + Employee(10008, 'Perry', 'Developer', 15000), + Employee(10009, 'Gable', 'Developer', 15000), + Employee(10010, 'Grimes', 'Developer', 15000), + ]; +} class EmployeeDataSource extends DataGridSource { - EmployeeDataSource() { + static final List _employees = []; + + EmployeeDataSource({required List employeeData}) { + _employees.addAll(employeeData); buildDataGridRows(); } @@ -329,23 +438,27 @@ class EmployeeDataSource extends DataGridSource { @override DataGridRowAdapter? buildRow(DataGridRow row) { return DataGridRowAdapter( - cells: row.getCells().map((dataGridCell) { - return Container( - alignment: (dataGridCell.columnName == 'id' || + cells: row.getCells().map((dataGridCell) { + return Container( + alignment: + (dataGridCell.columnName == 'id' || dataGridCell.columnName == 'salary') ? Alignment.centerRight : Alignment.centerLeft, - padding: EdgeInsets.symmetric(horizontal: 16.0), + padding: const EdgeInsets.symmetric(horizontal: 16.0), child: Text( dataGridCell.value.toString(), overflow: TextOverflow.ellipsis, - )); - }).toList()); + ), + ); + }).toList(), + ); } @override Future handleLoadMoreRows() async { - await Future.delayed(Duration(seconds: 5)); + // Simulate network delay for loading data + await Future.delayed(const Duration(seconds: 2)); _addMoreRows(_employees, 15); buildDataGridRows(); notifyListeners(); @@ -353,28 +466,38 @@ class EmployeeDataSource extends DataGridSource { void buildDataGridRows() { dataGridRows = _employees - .map((dataGridRow) => DataGridRow(cells: [ + .map( + (dataGridRow) => DataGridRow( + cells: [ DataGridCell(columnName: 'id', value: dataGridRow.id), DataGridCell(columnName: 'name', value: dataGridRow.name), DataGridCell( - columnName: 'designation', value: dataGridRow.designation), + columnName: 'designation', + value: dataGridRow.designation, + ), DataGridCell( - columnName: 'salary', value: dataGridRow.salary), - ])) + columnName: 'salary', + value: dataGridRow.salary, + ), + ], + ), + ) .toList(); } void _addMoreRows(List employees, int count) { - final Random _random = Random(); + final Random random = Random(); final startIndex = employees.isNotEmpty ? employees.length : 0, endIndex = startIndex + count; for (int i = startIndex; i < endIndex; i++) { - employees.add(Employee( - 1000 + i, - _names[_random.nextInt(_names.length - 1)], - _designation[_random.nextInt(_designation.length - 1)], - 10000 + _random.nextInt(10000), - )); + employees.add( + Employee( + 1000 + i, + _names[random.nextInt(_names.length)], + _designation[random.nextInt(_designation.length)], + 10000 + random.nextInt(10000), + ), + ); } } @@ -393,7 +516,7 @@ class EmployeeDataSource extends DataGridSource { 'Riscu', 'Seves', 'Vaffe', - 'Alfki' + 'Alfki', ]; final List _designation = [ @@ -402,14 +525,36 @@ class EmployeeDataSource extends DataGridSource { 'Manager', 'Designer', 'System Analyst', - 'CEO' + 'CEO', ]; } {% endhighlight %} {% endtabs %} -**NOTE** - Download demo application from [GitHub](https://github.com/SyncfusionExamples/how-to-load-rows-on-demand-in-Syncfusion-Flutter-datatable). +> **Note:** Download the demo application from [GitHub](https://github.com/SyncfusionExamples/how-to-load-rows-on-demand-in-Syncfusion-Flutter-datatable). ![flutter datagrid shows load more button behavior](images/load-more/flutter-datagrid-load-more-button.gif) + +## Choosing between infinite scrolling and button approach + +- **Infinite scrolling**: Best for continuous data browsing experiences where users don't need explicit control. Data loads automatically when they reach the bottom, creating a seamless experience. +- **Load more button**: Best when you want to give users explicit control over when data loads, or when automatic loading might consume excessive network bandwidth. + +## Best practices + +- **Batch size**: Load rows in reasonable batches (e.g., 10-20 rows) to balance performance and user experience. +- **Loading state**: Always provide visual feedback while loading to indicate that data is being fetched. +- **Handling completion**: When all data is loaded, modify your data source to stop triggering load operations. You can implement a flag to track this: + + ```dart + @override + Future handleLoadMoreRows() async { + if (_hasMoreData) { + // Load rows + _hasMoreData = _employees.length < _totalRecords; + } + } + ``` + +- **Error handling**: Implement proper error handling in your load more logic to gracefully handle network failures and retry options. diff --git a/Flutter/datagrid/localization.md b/Flutter/datagrid/localization.md index ed0ec0a38..fabd0e3e5 100644 --- a/Flutter/datagrid/localization.md +++ b/Flutter/datagrid/localization.md @@ -13,6 +13,8 @@ documentation: ug ### Localization in filter pop-up menu By default, the [SfDataGrid](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid-class.html) filter popup menu supports US English localizations. You can change the other languages by specifying the `MaterialApp` properties and adding the `flutter_localizations` and [syncfusion_localizations](https://pub.dev/packages/syncfusion_localizations) package to your application. +The following locales are supported: Chinese (zh), Arabic (ar), Japanese (ja), Hindi (hi), French (fr), German (de), Spanish (es), Portuguese (pt), Russian (ru), and more. If a locale is not specified in `supportedLocales`, the app defaults to the first supported locale. + To use `flutter_localizations` and `syncfusion_localizations`, add the package as a dependency to the `pubspec.yaml` file. {% highlight dart %} @@ -20,10 +22,12 @@ To use `flutter_localizations` and `syncfusion_localizations`, add the package a dependencies: flutter_localizations: sdk: flutter -syncfusion_localizations: ^24.2.7 +syncfusion_localizations: ^34.1.29 {% endhighlight %} +> **Note:** Run `flutter pub get` to fetch the newly added dependencies. + Next, import the `flutter_localizations` and `syncfusion_localizations` library. {% highlight dart %} @@ -33,7 +37,7 @@ import 'package:syncfusion_localizations/syncfusion_localizations.dart'; {% endhighlight %} -Then, declare the [SfGlobalLocalizations.delegate](https://pub.dev/documentation/syncfusion_localizations/latest/syncfusion_localizations/SfGlobalLocalizations/delegate-constant.html) in the `localizationsDelegates,` which is used to localize the static string available in the data pager and specify the `supportedLocales` as well. +Then, declare the [SfGlobalLocalizations.delegate](https://pub.dev/documentation/syncfusion_localizations/latest/syncfusion_localizations/SfGlobalLocalizations/delegate-constant.html) in the `localizationsDelegates,` which is used to localize the static strings available in the filter popup and specify the `supportedLocales` as well. {% tabs %} {% highlight Dart %} @@ -44,13 +48,9 @@ Then, declare the [SfGlobalLocalizations.delegate](https://pub.dev/documentation localizationsDelegates: const [ GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, - SfGlobalLocalizations.delegate - ], - supportedLocales: const [ - Locale('zh'), - Locale('ar'), - Locale('ja'), + SfGlobalLocalizations.delegate, ], + supportedLocales: const [Locale('zh'), Locale('ar'), Locale('ja')], locale: const Locale('ar'), home: Scaffold( appBar: AppBar( @@ -58,41 +58,47 @@ Then, declare the [SfGlobalLocalizations.delegate](https://pub.dev/documentation title: const Text('Syncfusion Flutter DataGrid'), ), body: SfDataGrid( - source: employeeDataSource, + source: _employeeDataSource, columnWidthMode: ColumnWidthMode.fill, gridLinesVisibility: GridLinesVisibility.both, headerGridLinesVisibility: GridLinesVisibility.both, allowFiltering: true, columns: [ GridColumn( - columnName: 'id', - label: Container( - padding: const EdgeInsets.all(16.0), - alignment: Alignment.center, - child: const Text( - 'ID', - ))), + 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'))), + 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, - ))), + 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'))), + columnName: 'salary', + label: Container( + padding: const EdgeInsets.all(8.0), + alignment: Alignment.center, + child: const Text('Salary'), + ), + ), ], ), ), @@ -102,13 +108,22 @@ Then, declare the [SfGlobalLocalizations.delegate](https://pub.dev/documentation {% endhighlight %} {% endtabs %} +> **Note:** After adding the packages, hot reload or restart your app to apply the localization changes. + flutter datagrid localization ## Localization in Flutter DataPager (SfDataPager) -By default, the [SfDataPager](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager-class.html) widget supports US English localizations. You can change the other languages by specifying the `MaterialApp` properties and adding the `flutter_localizations` package to your application. +By default, the [SfDataPager](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager-class.html) widget supports US English localizations. You can change the language by specifying the `MaterialApp` properties and adding the necessary localization packages to your application. + +The [SfDataPager](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager-class.html) supports two localization scenarios: -To use `flutter_localizations`, add the package as a dependency to the `pubspec.yaml` file. +1. **Basic localization (UI labels)** - Using `flutter_localizations` +2. **Complete localization (static strings)** - Using both `flutter_localizations` and `syncfusion_localizations` + +### Basic DataPager Localization + +To localize the basic UI elements, add `flutter_localizations` to your `pubspec.yaml` file: {% highlight dart %} @@ -118,198 +133,272 @@ flutter_localizations: {% endhighlight %} -Next, import the `flutter_localizations` library and specify [localizationsDelegates](https://api.flutter.dev/flutter/widgets/LocalizationsDelegate-class.html) and `supportedLocales` for `MaterialApp`. +> **Note:** Run `flutter pub get` to fetch the newly added dependency. + +Next, import the `flutter_localizations` library and specify [localizationsDelegates](https://api.flutter.dev/flutter/widgets/LocalizationsDelegate-class.html) and `supportedLocales` for `MaterialApp`: {% tabs %} {% highlight Dart %} import 'package:flutter_localizations/flutter_localizations.dart'; + List _employees = []; + late EmployeeDataSource _employeeDataSource; final int rowsPerPage = 15; + @override + void initState() { + super.initState(); + _employees = getEmployeeData(); + _employeeDataSource = EmployeeDataSource(employeeData: _employees); + } + @override Widget build(BuildContext context) { return MaterialApp( - localizationsDelegates: [ - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - ], - supportedLocales: [ - const Locale('zh'), - const Locale('ar'), - const Locale('ja'), - ], - locale: const Locale('zh'), - home: Scaffold( - appBar: AppBar( - title: Text('DataPager'), - ), - body: LayoutBuilder(builder: (context, constraints) { - return Column(children: [ + localizationsDelegates: const [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ], + supportedLocales: const [Locale('zh'), Locale('ar'), Locale('ja')], + locale: const Locale('ar'), + home: Scaffold( + appBar: AppBar(title: const Text('DataPager')), + body: LayoutBuilder( + builder: (context, constraints) { + return Column( + children: [ + SizedBox( + height: constraints.maxHeight - 60, + width: constraints.maxWidth, + child: SfDataGrid( + source: _employeeDataSource, + allowFiltering: true, + columns: [ + GridColumn( + columnName: 'id', + label: Center(child: Text('ID')), + ), + GridColumn( + columnName: 'name', + label: Center(child: Text('Name')), + ), + GridColumn( + columnName: 'designation', + label: Center(child: Text('Designation')), + ), + GridColumn( + columnName: 'salary', + label: Center(child: Text('Salary')), + ), + ], + ), + ), SizedBox( - height: constraints.maxHeight - 60, - width: constraints.maxWidth, - 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, - ))) - ])), - Container( - height: 60, - width: constraints.maxWidth, - child: SfDataPager( - delegate: _employeeDataSource, - pageCount: _employees.length / rowsPerPage, - visibleItemsCount: 5, - direction: Axis.horizontal, - )) - ]); - }))); + height: 60, + width: constraints.maxWidth, + child: SfDataPager( + delegate: _employeeDataSource, + pageCount: _employeeDataSource.rows.length / rowsPerPage, + visibleItemsCount: 5, + direction: Axis.horizontal, + ), + ), + ], + ); + }, + ), + ), + ); + } + +class EmployeeDataSource extends DataGridSource { + EmployeeDataSource({required List employeeData}) { + _employeeData = employeeData; } + late List _employeeData; + + @override + List get rows => _employeeData + .map( + (dataRow) => DataGridRow( + cells: [ + DataGridCell(columnName: 'id', value: dataRow.id), + DataGridCell(columnName: 'name', value: dataRow.name), + DataGridCell( + columnName: 'designation', + value: dataRow.designation, + ), + DataGridCell(columnName: 'salary', value: dataRow.salary), + ], + ), + ) + .toList(); + + @override + DataGridRowAdapter? buildRow(DataGridRow row) { + return DataGridRowAdapter( + cells: row.getCells().map((dataCell) { + return Container( + alignment: Alignment.center, + padding: const EdgeInsets.all(8.0), + child: Text(dataCell.value.toString()), + ); + }).toList(), + ); + } +} + {% endhighlight %} {% endtabs %} -## Localize the static string in DataPager +> **Note:** After adding the packages, hot reload or restart your app to apply the localization changes. + +flutter datagrid localization + +### Localize Static Strings in DataPager -Static strings in the data pager can be localized using the [syncfusion_localizations](https://pub.dev/packages/syncfusion_localizations) package and specifying `localizationsDelegates` in `MaterialApp`. +Static strings in the [SfDataPager](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager-class.html) (such as pagination labels and navigation text) can be localized using the [syncfusion_localizations](https://pub.dev/packages/syncfusion_localizations) package. -To use `syncfusion_localizations`, add the package as a dependency to the `pubspec.yaml` file. +To use `syncfusion_localizations`, add it as a dependency to the `pubspec.yaml` file: {% highlight dart %} dependencies: -syncfusion_localizations: ^18.3.35 +flutter_localizations: + sdk: flutter +syncfusion_localizations: ^34.1.29 {% endhighlight %} -Next, import the `syncfusion_localizations` library. +> **Note:** Run `flutter pub get` to fetch the newly added dependencies. + +Next, import both `flutter_localizations` and `syncfusion_localizations` libraries: {% highlight dart %} +import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:syncfusion_localizations/syncfusion_localizations.dart'; {% endhighlight %} -Then, declare the [SfGlobalLocalizations.delegate](https://pub.dev/documentation/syncfusion_localizations/latest/syncfusion_localizations/SfGlobalLocalizations/delegate-constant.html) in the `localizationsDelegates,` which is used to localize the static string available in the data pager and specify the `supportedLocales` as well. +Then, declare the [SfGlobalLocalizations.delegate](https://pub.dev/documentation/syncfusion_localizations/latest/syncfusion_localizations/SfGlobalLocalizations/delegate-constant.html) in the `localizationsDelegates,` which is used to localize the static strings available in the DataPager and specify the `supportedLocales` as well: {% tabs %} {% highlight Dart %} - final int rowsPerPage = 15; +final int rowsPerPage = 15; + +class Employee { + Employee(this.id, this.name, this.designation, this.salary); + + final int id; + final String name; + final String designation; + final int salary; +} @override Widget build(BuildContext context) { return MaterialApp( - localizationsDelegates: [ - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - SfGlobalLocalizations.delegate - ], - supportedLocales: [ - const Locale('zh'), - const Locale('ar'), - const Locale('ja'), - ], - locale: const Locale('zh'), - home: Scaffold( - appBar: AppBar( - title: Text('DataPager'), - ), - body: LayoutBuilder(builder: (context, constraints) { - return Column(children: [ + localizationsDelegates: const [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + SfGlobalLocalizations.delegate, + ], + supportedLocales: const [Locale('zh'), Locale('ar'), Locale('ja')], + locale: const Locale('zh'), + home: Scaffold( + appBar: AppBar(title: const Text('DataPager')), + body: LayoutBuilder( + builder: (context, constraints) { + return Column( + children: [ SizedBox( - height: constraints.maxHeight - 60, - width: constraints.maxWidth, - 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, - ))) - ])), - Container( - height: 60, - width: constraints.maxWidth, - child: SfDataPager( - delegate: _employeeDataSource, - pageCount: _employees.length / rowsPerPage, - visibleItemsCount: 5, - direction: Axis.horizontal, - )) - ]); - }))); + height: constraints.maxHeight - 60, + width: constraints.maxWidth, + child: SfDataGrid( + source: _employeeDataSource, + columns: [ + GridColumn( + columnName: 'id', + label: Center(child: Text('ID')), + ), + GridColumn( + columnName: 'name', + label: Center(child: Text('Name')), + ), + GridColumn( + columnName: 'designation', + label: Center(child: Text('Designation')), + ), + GridColumn( + columnName: 'salary', + label: Center(child: Text('Salary')), + ), + ], + ), + ), + SizedBox( + height: 60, + width: constraints.maxWidth, + child: SfDataPager( + delegate: _employeeDataSource, + pageCount: _employeeDataSource.rows.length / rowsPerPage, + visibleItemsCount: 5, + direction: Axis.horizontal, + ), + ), + ], + ); + }, + ), + ), + ); } +class EmployeeDataSource extends DataGridSource { + EmployeeDataSource({required List employeeData}) { + _employeeData = employeeData; + } + + late List _employeeData; + + @override + List get rows => _employeeData + .map( + (dataRow) => DataGridRow( + cells: [ + DataGridCell(columnName: 'id', value: dataRow.id), + DataGridCell(columnName: 'name', value: dataRow.name), + DataGridCell( + columnName: 'designation', + value: dataRow.designation, + ), + DataGridCell(columnName: 'salary', value: dataRow.salary), + ], + ), + ) + .toList(); + + @override + DataGridRowAdapter? buildRow(DataGridRow row) { + return DataGridRowAdapter( + cells: row.getCells().map((dataCell) { + return Container( + alignment: Alignment.center, + padding: const EdgeInsets.all(8.0), + child: Text(dataCell.value.toString()), + ); + }).toList(), + ); + } +} + {% endhighlight %} {% endtabs %} +> **Note:** After adding the packages, hot reload or restart your app to apply the localization changes. Supported locales include Chinese (zh), Arabic (ar), Japanese (ja), Hindi (hi), French (fr), German (de), Spanish (es), Portuguese (pt), Russian (ru), and more. See [SfGlobalLocalizations](https://pub.dev/documentation/syncfusion_localizations/latest/syncfusion_localizations/SfGlobalLocalizations-class.html) for the complete list. + flutter datagrid localization diff --git a/Flutter/datagrid/overview.md b/Flutter/datagrid/overview.md index e96dbc37f..c1651dc37 100644 --- a/Flutter/datagrid/overview.md +++ b/Flutter/datagrid/overview.md @@ -13,27 +13,53 @@ The Syncfusion® Flutter DataGrid is used to display and manipulate data in a ta ![Overview Flutter Datagrid](images/overview/flutter-datagrid-overview.png) - ## Key Features -* **Column types** - Display any widget in each column, allowing for flexible content presentation. -* **Column sizing** - Configure column widths with various sizing options. Automatically adjust columns based on cell content to enhance readability. -* **Row height** - Customize heights for header and data rows. Automatically adjust row heights based on cell content. Set different heights for specific rows as needed. -* **Editing** - Enable users to modify cell values with support for custom editor widgets based on column types. -* **Sorting** - Sort data in ascending or descending order across single or multiple columns. -* **Selection** - Select one or more rows with keyboard navigation support for web platforms. -* **Filtering** - Filter data interactively similar to Excel with support for text, numeric, and date-time filtering. Programmatic filtering is also available. -* **Column Drag and Drop** - Reorder columns by dragging and dropping them to desired positions. -* **Column resizing** - Adjust column widths by dragging the right edge of column headers. -* **Exporting** - Export data to Excel and PDF formats. -* **Styling** - Customize the appearance of cells and headers with support for conditional styling. -* **Stacked headers** - Create unbound header rows that span across multiple rows and columns. -* **Load more** - Display an interactive view when scrolling reaches the bottom of the grid, enabling on-demand data loading. -* **Paging** - Load data in segments. It is useful when loading huge amounts of data. -* **Freeze Panes** - Freeze the rows and columns when scrolling the grid. -* **Swiping** - Implement swipe actions (left-to-right or right-to-left) for operations like deleting or editing rows. -* **Footer** - Show an additional row that can be displayed under the last row. Widgets can also be displayed in the footer row. -* **Pull to refresh** - Allows users to refresh data when the DataGrid is pulled down. -* **Theme** - Use a dark or light theme. -* **Accessibility** - Ensure screen readers can properly access and navigate the DataGrid. -* **Right to Left (RTL)** - Support right-to-left layouts for languages like Hebrew and Arabic. +### Data Presentation +* [**Column types**](column-types.md) - Display any widget in each column, allowing for flexible content presentation. +* [**Column sizing**](columns-sizing.md) - Configure column widths with various sizing options. Automatically adjust columns based on cell content to enhance readability. +* [**Row height**](row-height-customization.md) - Customize heights for header and data rows. Automatically adjust row heights based on cell content. Set different heights for specific rows as needed. +* [**Styling**](styles.md) - Customize the appearance of cells and headers with support for conditional styling. +* [**Stacked headers**](stacked-headers.md) - Create unbound header rows that span across multiple rows and columns. +* [**Footer**](footer.md) - Show an additional row that can be displayed under the last row. Widgets can also be displayed in the footer row. + +### Data Manipulation +* [**Editing**](editing.md) - Enable users to modify cell values with support for custom editor widgets based on column types. +* [**Sorting**](sorting.md) - Sort data in ascending or descending order across single or multiple columns. +* [**Filtering**](filtering.md) - Filter data interactively similar to Excel with support for text, numeric, and date-time filtering. Programmatic filtering is also available. +* [**Selection**](selection.md) - Select one or more rows with keyboard navigation support for web platforms. +* [**Swiping**](swiping.md) - Implement swipe actions (left-to-right or right-to-left) for operations like deleting or editing rows. + +### Layout and Navigation +* [**Column Drag and Drop**](column-drag-and-drop.md) - Reorder columns by dragging and dropping them to desired positions. +* [**Column resizing**](columns-resizing.md) - Adjust column widths by dragging the right edge of column headers. +* [**Freeze Panes**](freeze-panes.md) - Freeze the rows and columns when scrolling the grid. +* [**Scrolling**](scrolling.md) - Scroll through large datasets efficiently with optimized rendering. + +### Data Loading and Performance +* [**Load more**](load-more.md) - Display an interactive view when scrolling reaches the bottom of the grid, enabling on-demand data loading. +* [**Paging**](paging.md) - Load data in segments. It is useful when loading huge amounts of data. +* [**Pull to refresh**](pull-to-refresh.md) - Allows users to refresh data when the DataGrid is pulled down. + +### Export and Integration +* [**Exporting**](export-to-excel.md) - Export data to [Excel](export-to-excel.md) and [PDF](export-to-pdf.md) formats. +* [**Grouping**](grouping.md) - Group rows by one or more columns for better data organization. +* [**Summaries**](summaries.md) - Display aggregate values for grouped or all data. + +### Customization and Accessibility +* [**Theme**](https://help.syncfusion.com/flutter/themes) - Use a dark or light theme. +* [**Accessibility**](accessibility.md) - Ensure screen readers can properly access and navigate the DataGrid. +* [**Right to Left (RTL)**](right-to-left.md) - Support right-to-left layouts for languages like Hebrew and Arabic. +* [**Localization**](localization.md) - Support multiple languages and regional formats. + +## Getting Started + +To start using the SfDataGrid widget in your Flutter application, refer to the [Getting Started with Flutter DataGrid](getting-started.md) documentation. + +## API Reference + +For a complete list of properties, methods, and events of the SfDataGrid widget, refer to the [SfDataGrid API documentation](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid-class.html). + +## Sample GitHub Repository + +You can download a complete working sample from the [GitHub repository](https://github.com/SyncfusionExamples/getting-started-with-flutter-datagrid) to explore the SfDataGrid widget with various features implemented. diff --git a/Flutter/datagrid/paging.md b/Flutter/datagrid/paging.md index f3c4fb7e0..59f05de34 100644 --- a/Flutter/datagrid/paging.md +++ b/Flutter/datagrid/paging.md @@ -9,23 +9,42 @@ documentation: ug # Paging in Flutter DataGrid (SfDataGrid) -The Datagrid interactively supports the manipulation of data using the [SfDataPager](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager-class.html) control. This provides support to load data in segments when dealing with large volumes of data. The `SfDataPager` can be placed above or under based on the requirement to easily manage data paging. +The SfDataGrid interactively supports the manipulation of data using the [SfDataPager](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager-class.html) control. This provides support to load data in segments when dealing with large volumes of data. The `SfDataPager` can be placed above or below the SfDataGrid based on your requirement to easily manage data paging. -The Datagrid performs paging of data using the `SfDataPager`. To enable paging, follow this procedure +The SfDataGrid performs paging of data using the `SfDataPager`. To enable paging, follow these steps * Create a new `SfDataPager` widget, and set the [SfDataGrid.DataGridSource](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource-class.html) to the [SfDataPager.delegate](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/delegate.html) property. -* Set the number of pages required to be displayed in the data pager by setting the [SfDataPager.pageCount](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/pageCount.html) property. +* Set the number of pages required to be displayed in the data pager by setting the [SfDataPager.pageCount](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/pageCount.html) property to a `double` value. * Set the number of buttons that should be displayed in view by setting the [SfDataPager.visibleItemsCount](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/visibleItemsCount.html) property. -* Load the data for a specific page in the [handlePageChange](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/handlePageChange.html) method. This method is called for every page navigation from the data pager. +* Load the data for a specific page in the [handlePageChange](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/handlePageChange.html) method. This method is called for every page navigation from the data pager. The method notifies listeners to refresh the UI. -N> The `SfDataPager.visibleItemsCount` property default value is 5. +> **Note:** +>- The `SfDataPager.visibleItemsCount` property default value is 5. +>- Required imports - Ensure you have imported `syncfusion_flutter_datagrid`, `syncfusion_flutter_core`, and any data model classes. The `DataGridSource` is an abstract class that you must extend with your custom implementation. -The following code example illustrates using the `SfDataPager` with the Datagrid control: +The following code example illustrates using the `SfDataPager` with the SfDataGrid control: {% tabs %} {% highlight Dart %} import 'package:intl/intl.dart'; +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; +import 'package:syncfusion_flutter_core/theme.dart'; + +// Define OrderInfo model class +class OrderInfo { + OrderInfo({ + required this.orderID, + required this.customerID, + required this.orderDate, + required this.freight, + }); + + final int orderID; + final String customerID; + final DateTime orderDate; + final double freight; +} final int _rowsPerPage = 15; final double _dataPagerHeight = 60.0; @@ -45,7 +64,7 @@ import 'package:intl/intl.dart'; height: _dataPagerHeight, child: SfDataPager( delegate: _orderInfoDataSource, - pageCount: _orders.length / _rowsPerPage, + pageCount: (_orders.length / _rowsPerPage).ceil().toDouble(), direction: Axis.horizontal, )) ]); @@ -98,7 +117,9 @@ import 'package:intl/intl.dart'; class OrderInfoDataSource extends DataGridSource { OrderInfoDataSource() { - _paginatedOrders = _orders.getRange(0, 19).toList(growable: false); + _paginatedOrders = _orders.isNotEmpty + ? _orders.getRange(0, _orders.length > _rowsPerPage ? _rowsPerPage : _orders.length).toList(growable: false) + : []; buildPaginatedDataGridRows(); } @@ -185,9 +206,9 @@ class OrderInfoDataSource extends DataGridSource { ## Callbacks -The SfDataPager provides the [onPageNavigationStart](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/onPageNavigationStart.html) and [onPageNavigationEnd](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/onPageNavigationEnd.html) callbacks to listen to the page navigation at the widget level. +The [SfDataPager](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager-class.html) provides the [onPageNavigationStart](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/onPageNavigationStart.html) and [onPageNavigationEnd](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/onPageNavigationEnd.html) callbacks to listen to page navigation at the widget level. -Typically, these callbacks are used to show and hide the loading indicator. +Typically, these callbacks are used to show and hide a loading indicator during page transitions. {% tabs %} {% highlight Dart %} @@ -205,14 +226,14 @@ Typically, these callbacks are used to show and hide the loading indicator. height: 60, width: constraints.maxWidth, child: SfDataPager( - pageCount: _orders.length / _rowsPerPage, + pageCount: (_orders.length / _rowsPerPage).ceil().toDouble(), direction: Axis.horizontal, onPageNavigationStart: (int pageIndex) { - //You can do your customization + // Customize this callback when page navigation begins }, delegate: _orderInfoDataSource, onPageNavigationEnd: (int pageIndex) { - //You can do your customization + // Customize this callback when page navigation completes })) ]) ]); @@ -224,18 +245,18 @@ Typically, these callbacks are used to show and hide the loading indicator. ## Asynchronous data loading -You can load the data asynchronously to the `SfDataPager` by overriding the `handlePageChange` method and await the method while loading the data. +You can load data asynchronously to the `SfDataPager` by overriding the [handlePageChange](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/handlePageChange.html) method and awaiting the data fetch operation. -You can use `onPageNavigationStart` and `onPageNavigationEnd` callbacks to show and hide the loading indicator when navigating between pages. +Use the `onPageNavigationStart` and `onPageNavigationEnd` callbacks to show and hide a loading indicator when navigating between pages. -In the below example, we have set await for 2000ms and displayed the loading indicator until 2000ms. +In the below example, we simulate asynchronous data loading with a 2000ms delay and display the loading indicator during this time. {% tabs %} {% highlight Dart %} import 'package:intl/intl.dart'; - bool showLoadingIndicator = true; + bool showLoadingIndicator = false; @override Widget build(BuildContext context) { @@ -250,7 +271,7 @@ import 'package:intl/intl.dart'; height: 60, width: constraints.maxWidth, child: SfDataPager( - pageCount: _orders.length / _rowsPerPage, + pageCount: (_orders.length / _rowsPerPage).ceil().toDouble(), direction: Axis.horizontal, onPageNavigationStart: (int pageIndex) { setState(() { @@ -295,7 +316,9 @@ import 'package:intl/intl.dart'; class OrderInfoDataSource extends DataGridSource { OrderInfoDataSource() { - _paginatedOrders = _orders.getRange(0, 19).toList(growable: false); + _paginatedOrders = _orders.isNotEmpty + ? _orders.getRange(0, _orders.length > _rowsPerPage ? _rowsPerPage : _orders.length).toList(growable: false) + : []; buildPaginatedDataGridRows(); } @@ -381,25 +404,36 @@ class OrderInfoDataSource extends DataGridSource { ![flutter datapager with asynchronous loading](images/paging/flutter-datapager-asynchronous-loading.gif) ->**NOTE** - Download demo application from [GitHub](https://github.com/SyncfusionExamples/how-to-show-loading-indicator-on-loading-page-in-flutter-datatable). +> **Note:** Download a complete demo application from [GitHub](https://github.com/SyncfusionExamples/how-to-show-loading-indicator-on-loading-page-in-flutter-datatable). ## Programmatic page navigation -The `SfDataPager` provides the support to navigate between the pages programmatically using a [controller](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController-class.html) with the following options. +The `SfDataPager` provides support to navigate between pages programmatically using a [DataPagerController](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataPagerController-class.html) with the following methods: -* [nextPage](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataPagerController/nextPage.html) -* [previousPage](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataPagerController/previousPage.html) -* [LastPage](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataPagerController/lastPage.html) -* [firstPage](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataPagerController/firstPage.html) +* [nextPage()](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataPagerController/nextPage.html) - Navigate to the next page +* [previousPage()](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataPagerController/previousPage.html) - Navigate to the previous page +* [lastPage()](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataPagerController/lastPage.html) - Navigate to the last page +* [firstPage()](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataPagerController/firstPage.html) - Navigate to the first page -The following code example shows how to navigate the previous page programmatically, +The following code example shows how to navigate to the previous page programmatically: {% tabs %} {% highlight Dart %} - DataPagerController _controller = DataPagerController(); + late DataPagerController _controller; + + @override + void initState() { + super.initState(); + _controller = DataPagerController(); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } @override Widget build(BuildContext context) { @@ -409,7 +443,7 @@ The following code example shows how to navigate the previous page programmatica onPressed: () { _controller.previousPage(); }, - child: Text('Move Previous page'), + child: Text('Move to Previous Page'), ), SizedBox( height: constraint.maxHeight - 120, @@ -423,7 +457,7 @@ The following code example shows how to navigate the previous page programmatica delegate: _orderInfoDataSource, initialPageIndex: 2, controller: _controller, - pageCount: _orders.length / _rowsPerPage, + pageCount: (_orders.length / _rowsPerPage).ceil().toDouble(), direction: Axis.horizontal, ))) ]); @@ -435,20 +469,25 @@ The following code example shows how to navigate the previous page programmatica ## Show dropdown button to choose rows per page -Show the dropdown button option to select a different number of rows per page by defining the [onRowPerPageChanged](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/onRowsPerPageChanged.html) callback. If it is null, no option will be provided to select a different number of rows per page. +Display a dropdown button option to select a different number of rows per page by defining the [onRowsPerPageChanged](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/onRowsPerPageChanged.html) callback. If it is null, no option will be provided to change the number of rows per page. -Use the [availableRowsPerPage](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/availableRowsPerPage.html) property to define the list of numbers to be displayed in the drop-down. The default value of the `availableRowsPerPage` property is [10,15,20]. +Use the [availableRowsPerPage](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/availableRowsPerPage.html) property to define the list of row counts displayed in the dropdown. The default value is [10, 15, 20]. ->**NOTE** - You can view dropdown button option by horizontally scrolling the DataPager. The dropdown button option is not supported, if the [direction](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/direction.html) is vertical. +> **Note:** You can view the dropdown button by horizontally scrolling the SfDataPager. The dropdown button option is not supported when the [direction](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/direction.html) property is set to vertical. {% tabs %} {% highlight Dart %} - int _rowsPerPage=10; + int _rowsPerPage = 10; List employees = []; late EmployeeDataSource employeeDataSource; double datapagerHeight = 70.0; + final List _column = [ + GridColumn(columnName: 'id', label: Container(child: Text('ID'))), + GridColumn(columnName: 'name', label: Container(child: Text('Name'))), + GridColumn(columnName: 'designation', label: Container(child: Text('Designation'))), + GridColumn(columnName: 'salary', label: Container(child: Text('Salary'))), + ]; @override void initState() { @@ -482,18 +521,17 @@ Use the [availableRowsPerPage](https://pub.dev/documentation/syncfusion_flutter_ onRowsPerPageChanged: (int? rowsPerPage) { setState(() { _rowsPerPage = rowsPerPage!; - employeeDataSource.updateDataGriDataSource(); + employeeDataSource.updateDataGridDataSource(); }); }, - pageCount: - ((employees.length / _rowsPerPage).ceil()).toDouble(), + pageCount: ((employees.length / _rowsPerPage).ceil()).toDouble(), )), ], ); })); } - class EmployeeDataSource extends DataGridSource { +class EmployeeDataSource extends DataGridSource { /// Creates the employee data source class with required details. EmployeeDataSource({required List employeeData}) { _employeeData = employeeData; @@ -534,16 +572,16 @@ Use the [availableRowsPerPage](https://pub.dev/documentation/syncfusion_flutter_ @override Future handlePageChange(int oldPageIndex, int newPageIndex) { - final int _startIndex = newPageIndex * _rowsPerPage; - int _endIndex = _startIndex + _rowsPerPage; - if (_endIndex > _employeeData.length) { - _endIndex = _employeeData.length; + final int startIndex = newPageIndex * _rowsPerPage; + int endIndex = startIndex + _rowsPerPage; + if (endIndex > _employeeData.length) { + endIndex = _employeeData.length; } - /// Get a particular range from the sorted collection. - if (_startIndex < _employeeData.length && - _endIndex <= _employeeData.length) { - _paginatedRows = _employeeData.getRange(_startIndex, _endIndex).toList(); + // Get a particular range from the data collection. + if (startIndex < _employeeData.length && + endIndex <= _employeeData.length) { + _paginatedRows = _employeeData.getRange(startIndex, endIndex).toList(); } else { _paginatedRows = []; } @@ -552,10 +590,10 @@ Use the [availableRowsPerPage](https://pub.dev/documentation/syncfusion_flutter_ return Future.value(true); } - void updateDataGriDataSource() { + void updateDataGridDataSource() { notifyListeners(); } - } +} {% endhighlight %} {% endtabs %} @@ -563,30 +601,30 @@ Use the [availableRowsPerPage](https://pub.dev/documentation/syncfusion_flutter_ ## Orientation -`SfDataPager` allows you to arrange the child elements either horizontally or vertically. This can be achieved by using the [direction](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/direction.html) Property. `direction` is an Enum type. +`SfDataPager` allows you to arrange the navigation and page buttons either horizontally or vertically by using the [direction](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/direction.html) property. The `direction` property accepts an `Axis` enum value.
-Enum +Value Description
-horizontal +Axis.horizontal -This is the default enum value for direction. Arranges all the navigation buttons and numeric buttons horizontally.{{'![flutter datapager in horizontal direction](images/paging/flutter-datapager-direction-horizontal.png)'|markdownify}} +This is the default value. Arranges all navigation buttons and page number buttons horizontally.{{'![flutter datapager in horizontal direction](images/paging/flutter-datapager-direction-horizontal.png)'|markdownify}}
-vertical +Axis.vertical -Arranges all the navigation buttons and numeric buttons vertically by setting Axis.vertical to direction property.{{'![flutter datapager in vertical direction](images/paging/flutter-datapager-direction-vertical.png)'|markdownify}} +Arranges all navigation buttons and page number buttons vertically.{{'![flutter datapager in vertical direction](images/paging/flutter-datapager-direction-vertical.png)'|markdownify}}
@@ -594,19 +632,11 @@ Arranges all the navigation buttons and numeric buttons vertically by setting Ax ## Appearance -SfDataPager allows customizing the appearance of the data pager using the [SfDataPagerThemeData](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataPagerThemeData-class.html) in [SfDataPagerTheme](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataPagerTheme-class.html). The `SfDataPager` should be wrapped inside the `SfDataPagerTheme.` - -Import the following class from the [syncfusion_flutter_core](https://pub.dev/packages/syncfusion_flutter_core) package. - -{% tabs %} -{% highlight Dart %} - -import 'package:syncfusion_flutter_core/theme.dart'; +Customize the appearance of the SfDataPager using the [SfDataPagerThemeData](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataPagerThemeData-class.html) class within the [SfDataPagerTheme](https://pub.dev/documentation/syncfusion_flutter_core/latest/theme/SfDataPagerTheme-class.html) widget. Wrap the `SfDataPager` inside `SfDataPagerTheme` and configure the theme data. -{% endhighlight %} -{% endtabs %} +> **Note:** Import the theming package: `import 'package:syncfusion_flutter_core/theme.dart';` -The following code example illustrates using `SfDataPagerThemeData` with the data pager control +The following code example illustrates customizing the SfDataPager appearance: {% tabs %} {% highlight Dart %} @@ -623,7 +653,7 @@ The following code example illustrates using `SfDataPagerThemeData` with the dat ), child: SfDataPager( delegate: _orderInfoDataSource, - pageCount: _orders.length / _rowsPerPage, + pageCount: (_orders.length / _rowsPerPage).ceil().toDouble(), direction: Axis.horizontal, ), ), @@ -637,7 +667,7 @@ The following code example illustrates using `SfDataPagerThemeData` with the dat ### Set the padding between page items -The padding between the page items including navigation page items such as first, last, previous and next can be changed by using the [itemPadding](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/itemPadding.html) property. +The spacing between page number buttons and navigation buttons (first, last, previous, next) can be changed using the [itemPadding](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/itemPadding.html) property. {% tabs %} {% highlight Dart %} @@ -659,11 +689,11 @@ The padding between the page items including navigation page items such as first {% endhighlight %} {% endtabs %} -N> The default value of `SfDataPager.itemPadding` is 5.0. +> **Note:** The default value of `SfDataPager.itemPadding` is 5.0. ### Set the height and width of the page items -The default width and height of the page items are 50 and 50, respectively. For changing page number items size, use the [itemWidth](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/itemWidth.html) and [itemHeight](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/itemHeight.html) properties; for changing navigation items size such as first, last, previous, and next, use the [navigationItemHeight](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/navigationItemHeight.html) and [navigationItemWidth](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/navigationItemWidth.html) properties. +The default width and height of the page number buttons are 50 and 50, respectively. To customize the size of page number buttons, use the [itemWidth](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/itemWidth.html) and [itemHeight](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/itemHeight.html) properties. For customizing navigation button sizes (first, last, previous, next), use the [navigationItemHeight](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/navigationItemHeight.html) and [navigationItemWidth](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/navigationItemWidth.html) properties. {% tabs %} {% highlight Dart %} @@ -700,14 +730,14 @@ The default width and height of the page items are 50 and 50, respectively. For ### Hide certain navigation page items -To hide certain navigation page items, use the following properties: +To hide specific navigation buttons, use the following properties: - * [firstPageItemVisible](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/firstPageItemVisible.html) - * [lastPageItemVisible](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/lastPageItemVisible.html) - * [nextPageItemVisible](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/nextPageItemVisible.html) - * [previousPageItemVisible](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/previousPageItemVisible.html) + * [firstPageItemVisible](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/firstPageItemVisible.html) - Show/hide the first page button + * [lastPageItemVisible](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/lastPageItemVisible.html) - Show/hide the last page button + * [nextPageItemVisible](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/nextPageItemVisible.html) - Show/hide the next page button + * [previousPageItemVisible](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/previousPageItemVisible.html) - Show/hide the previous page button - N> Default value of all properties is true. + > **Note:** The default value for all these properties is `true`. {% tabs %} {% highlight Dart %} @@ -755,7 +785,7 @@ To hide certain navigation page items, use the following properties: ## Change the number of visible items (buttons) in the view -You can change the number of visible items i.e. page buttons in view by using the [SfDataPager.visibleItemsCount](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/visibleItemsCount.html). +You can control the number of page buttons displayed at once using the [visibleItemsCount](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/visibleItemsCount.html) property. {% tabs %} {% highlight Dart %} @@ -778,7 +808,7 @@ You can change the number of visible items i.e. page buttons in view by using th child: SfDataPager( visibleItemsCount: 1, delegate: _orderInfoDataSource, - pageCount: _orders.length / _rowsPerPage, + pageCount: (_orders.length / _rowsPerPage).ceil().toDouble(), direction: Axis.horizontal, ), ) @@ -792,7 +822,7 @@ You can change the number of visible items i.e. page buttons in view by using th ## Load any widget in the page button -Load any widget to the page button by using the [SfDataPager.pageItemBuilder](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/pageItemBuilder.html). +Customize the appearance of page buttons by providing a custom widget using the [pageItemBuilder](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataPager/pageItemBuilder.html) callback. {% tabs %} {% highlight Dart %} @@ -828,7 +858,7 @@ Load any widget to the page button by using the [SfDataPager.pageItemBuilder](ht )); }, delegate: _orderInfoDataSource, - pageCount: _orders.length / _rowsPerPage, + pageCount: (_orders.length / _rowsPerPage).ceil().toDouble(), direction: Axis.horizontal, ))) ]); @@ -838,11 +868,13 @@ Load any widget to the page button by using the [SfDataPager.pageItemBuilder](ht {% endhighlight %} {% endtabs %} -## Sort all the rows instead of rows available on a page +## Alternative: Automatic pagination without manual handlePageChange + +By default, when you override the `handlePageChange` method, you manually manage which rows to display for each page. However, if you want automatic pagination where sorting and filtering apply to all rows before pagination, do not override the `handlePageChange` method in the `DataGridSource` class. -By default, the rows on a page are sorted. To sort all the rows available for paging, do not override the `handlePageChange` method in the `DataGridSource` class. The DataGrid will automatically split the rows required for each page based on the `SfDataPager.pageCount`, i.e. the divided value of the [DataGridRows.rows](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/rows.html) and `SfDataPager.pageCount`. +When `handlePageChange` is not overridden, the SfDataGrid automatically splits the rows required for each page based on the `pageCount` property using the following formula: `pageCount = (total rows / rowsPerPage)`. -If you want to specifically maintain the rows required for a page, you can use the [SfDataGrid.rowsPerPage](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/rowsPerPage.html) property. However, make sure that you do not override the `handlePageChange` method in the `DataGridSource` class at the sample level. +Use the [rowsPerPage](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/rowsPerPage.html) property on the SfDataGrid to specify how many rows should appear per page. This approach ensures that operations like sorting apply to the entire dataset before pagination occurs. {% tabs %} {% highlight Dart %} @@ -969,6 +1001,9 @@ class OrderInfoDataSource extends DataGridSource { }).toList()); } + // Note: handlePageChange is NOT overridden in this example. + // The SfDataGrid automatically handles pagination and sorting. + void buildDataGridRows() { dataGridRows = _orders.map((dataGridRow) { return DataGridRow(cells: [ diff --git a/Flutter/datagrid/placeholder.md b/Flutter/datagrid/placeholder.md index 597fc7f38..c5c600cc6 100644 --- a/Flutter/datagrid/placeholder.md +++ b/Flutter/datagrid/placeholder.md @@ -7,9 +7,9 @@ control: SfDataGrid documentation: ug --- -# Placeholder in Flutter Datagrid (SfDataGrid) +# Placeholder in Flutter DataGrid (SfDataGrid) -The `SfDataGrid` provides built-in support for displaying a placeholder when the data source is empty by setting the [SfDataGrid.placeholder](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/placeholder.html) property. When the `SfDataGrid.placeholder` is set, the DataGrid automatically shows the specified widget in the scroll view area. By default, the `SfDataGrid` does not display anything when the data source is empty. +The `SfDataGrid` provides built-in support for displaying a placeholder when the data source is empty by setting the [SfDataGrid.placeholder](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/placeholder.html) property. The `placeholder` property accepts a `Widget` that will be displayed in the scroll view area when the DataGrid has no data to show. The following example shows how to add a `placeholder` in SfDataGrid: @@ -23,7 +23,7 @@ The following example shows how to add a `placeholder` in SfDataGrid: title: const Text('Syncfusion Flutter DataGrid'), ), body: SfDataGrid( - source: employeeDataSource, + source: _employeeDataSource, columnWidthMode: ColumnWidthMode.auto, columns: [ GridColumn( diff --git a/Flutter/datagrid/pull-to-refresh.md b/Flutter/datagrid/pull-to-refresh.md index fad9d4380..c9ed31c08 100644 --- a/Flutter/datagrid/pull-to-refresh.md +++ b/Flutter/datagrid/pull-to-refresh.md @@ -9,64 +9,100 @@ documentation: ug # Pull to Refresh in Flutter DataGrid (SfDataGrid) -The Flutter DataTable provides support to add more data at runtime by using the PullToRefresh feature. -You can simply enable the PullToRefresh option by setting the [SfDataGrid.allowPullToRefresh](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/allowPullToRefresh.html) property to `true` and override the [DataGridSource.handleRefresh](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/handleRefresh.html) method to include the data which is going to add to the data source at runtime and then notify the data grid about the changes. +The SfDataGrid provides support to add more data at runtime by using the pull-to-refresh feature. You can enable the pull-to-refresh option by setting the [SfDataGrid.allowPullToRefresh](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/allowPullToRefresh.html) property to `true` and overriding the [DataGridSource.handleRefresh](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/handleRefresh.html) method to add new data to the data source at runtime, then notify the data grid about the changes. {% tabs %} {% highlight Dart %} +import 'dart:math'; +import 'package:flutter/material.dart'; import 'package:syncfusion_flutter_datagrid/datagrid.dart'; - EmployeeDataSource _employeeDataSource = EmployeeDataSource(); +class Employee { + Employee(this.id, this.name, this.designation, this.salary); + + final int id; + final String name; + final String designation; + final int salary; +} + +class PullToRefreshDemoState extends State { + List _employees = []; + late EmployeeDataSource _employeeDataSource; + + @override + void initState() { + super.initState(); + _employees = getEmployeeData(); + _employeeDataSource = EmployeeDataSource(employeeData: _employees); + } @override Widget build(BuildContext context) { - return SfDataGrid( - allowPullToRefresh: true, - source: _employeeDataSource, - columns: [ - GridColumn( + return Scaffold( + body: SfDataGrid( + allowPullToRefresh: true, + source: _employeeDataSource, + columns: [ + GridColumn( columnName: 'id', label: Container( - padding: EdgeInsets.symmetric(horizontal: 16.0), - alignment: Alignment.centerRight, - child: Text( - 'ID', - overflow: TextOverflow.ellipsis, - ))), - GridColumn( + 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( + 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( + 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, - ))), - ], + padding: EdgeInsets.symmetric(horizontal: 16.0), + alignment: Alignment.centerRight, + child: Text('Salary', overflow: TextOverflow.ellipsis), + ), + ), + ], + ), ); } +} + +List getEmployeeData() { + return [ + Employee(10001, 'James', 'Project Lead', 20000), + Employee(10002, 'Kathryn', 'Manager', 30000), + Employee(10003, 'Lara', 'Developer', 15000), + Employee(10004, 'Michael', 'Designer', 15000), + Employee(10005, 'Martin', 'Developer', 15000), + Employee(10006, 'Newberry', 'Developer', 15000), + Employee(10007, 'Balnc', 'Developer', 15000), + Employee(10008, 'Perry', 'Developer', 15000), + Employee(10009, 'Gable', 'Developer', 15000), + Employee(10010, 'Grimes', 'Developer', 15000), + ]; +} class EmployeeDataSource extends DataGridSource { - EmployeeDataSource() { + late List _employees = []; + + EmployeeDataSource({required List employeeData}) { + _employees = employeeData; buildDataGridRows(); } @@ -78,9 +114,10 @@ class EmployeeDataSource extends DataGridSource { @override DataGridRowAdapter? buildRow(DataGridRow row) { return DataGridRowAdapter( - cells: row.getCells().map((dataGridCell) { - return Container( - alignment: (dataGridCell.columnName == 'id' || + cells: row.getCells().map((dataGridCell) { + return Container( + alignment: + (dataGridCell.columnName == 'id' || dataGridCell.columnName == 'salary') ? Alignment.centerRight : Alignment.centerLeft, @@ -88,13 +125,16 @@ class EmployeeDataSource extends DataGridSource { child: Text( dataGridCell.value.toString(), overflow: TextOverflow.ellipsis, - )); - }).toList()); + ), + ); + }).toList(), + ); } @override Future handleRefresh() async { - await Future.delayed(Duration(seconds: 5)); + // Simulate network delay for fetching new data from server + await Future.delayed(Duration(seconds: 2)); _addMoreRows(_employees, 15); buildDataGridRows(); notifyListeners(); @@ -102,28 +142,38 @@ class EmployeeDataSource extends DataGridSource { void buildDataGridRows() { dataGridRows = _employees - .map((dataGridRow) => DataGridRow(cells: [ + .map( + (dataGridRow) => DataGridRow( + cells: [ DataGridCell(columnName: 'id', value: dataGridRow.id), DataGridCell(columnName: 'name', value: dataGridRow.name), DataGridCell( - columnName: 'designation', value: dataGridRow.designation), + columnName: 'designation', + value: dataGridRow.designation, + ), DataGridCell( - columnName: 'salary', value: dataGridRow.salary), - ])) + columnName: 'salary', + value: dataGridRow.salary, + ), + ], + ), + ) .toList(); } void _addMoreRows(List employees, int count) { - final Random _random = Random(); - final startIndex = employees.isNotEmpty ? employees.length : 0, - endIndex = startIndex + count; + final Random random = Random(); + final startIndex = employees.isNotEmpty ? employees.length : 0; + final endIndex = startIndex + count; for (int i = startIndex; i < endIndex; i++) { - employees.add(Employee( - 1000 + i, - _names[_random.nextInt(_names.length - 1)], - _designation[_random.nextInt(_designation.length - 1)], - 10000 + _random.nextInt(10000), - )); + employees.add( + Employee( + 1000 + i, + _names[random.nextInt(_names.length)], + _designation[random.nextInt(_designation.length)], + 10000 + random.nextInt(10000), + ), + ); } } @@ -142,7 +192,7 @@ class EmployeeDataSource extends DataGridSource { 'Riscu', 'Seves', 'Vaffe', - 'Alfki' + 'Alfki', ]; final List _designation = [ @@ -151,14 +201,14 @@ class EmployeeDataSource extends DataGridSource { 'Manager', 'Designer', 'System Analyst', - 'CEO' + 'CEO', ]; } {% endhighlight %} {% endtabs %} -Download the demo application from [GitHub](https://github.com/SyncfusionExamples/pull-to-refresh-support-in-flutter-datatable-sfdatagrid). +> **Reference:** Download the demo application from [GitHub](https://github.com/SyncfusionExamples/pull-to-refresh-support-in-flutter-datatable-sfdatagrid). ![flutter datagrid shows default view of refresh indicator](images/pull-to-refresh/flutter-datagrid-pull-to-refresh.gif) @@ -173,135 +223,266 @@ To set the indicator's color and background color, use the [ColorScheme](https:/ {% tabs %} {% highlight Dart %} +import 'package:flutter/material.dart'; import 'package:syncfusion_flutter_datagrid/datagrid.dart'; +class CustomRefreshIndicatorDemoState + extends State { + List _employees = []; + late EmployeeDataSource _employeeDataSource; + + @override + void initState() { + super.initState(); + _employees = getEmployeeData(); + _employeeDataSource = EmployeeDataSource(employeeData: _employees); + } + @override Widget build(BuildContext context) { - return Theme( + return Scaffold( + body: Theme( data: ThemeData( - brightness: Brightness.light, - canvasColor: Colors.lightBlue, - colorScheme: const ColorScheme.light( - primary: Colors.white)), + brightness: Brightness.light, + canvasColor: Colors.lightBlue, + colorScheme: const ColorScheme.light(primary: Colors.white), + ), child: SfDataGrid( - allowPullToRefresh: true, - source: _employeeDataSource, - refreshIndicatorStrokeWidth: 3.0, - refreshIndicatorDisplacement: 60.0, - 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, - ))), - ])); + allowPullToRefresh: true, + source: _employeeDataSource, + refreshIndicatorStrokeWidth: 3.0, + refreshIndicatorDisplacement: 60.0, + 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), + ), + ), + ], + ), + ), + ); } +} {% endhighlight %} {% endtabs %} -Download the demo application from [GitHub](https://github.com/SyncfusionExamples/how-to-customize-the-refresh-indicator-appearance-in-flutter-datatable-sfdatagrid). +> **Reference:** Download the demo application from [GitHub](https://github.com/SyncfusionExamples/how-to-customize-the-refresh-indicator-appearance-in-flutter-datatable-sfdatagrid). ![flutter datagrid shows customized refresh indicator](images/pull-to-refresh/flutter-datagrid-customized-pull-to-refresh-indicator.gif) ## Programmatic Pull to Refresh -If you want to refresh data without showing a refresh indicator, pass `false` to the `showRefreshIndicator` optional parameter of the [refresh](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGridState/refresh.html) method. By doing this, the `DataGridSource.handleRefresh` method will be called without showing the `RefreshIndicator` in UI. +You can trigger data refresh programmatically using the [SfDataGridState.refresh()](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGridState/refresh.html) method. By default, the refresh indicator is displayed during the refresh operation. To refresh data without showing the refresh indicator, pass `false` to the `showRefreshIndicator` parameter. + +The `refresh()` method calls the [DataGridSource.handleRefresh()](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/handleRefresh.html) method, which is a `Future` that returns when the refresh operation completes. If an exception occurs during `handleRefresh()`, the data grid will handle it gracefully and the refresh state will be reset. + +> **Note:** Use a `GlobalKey` to access the refresh method from outside the SfDataGrid widget. {% tabs %} {% highlight Dart %} +import 'dart:math'; +import 'package:flutter/material.dart'; import 'package:syncfusion_flutter_datagrid/datagrid.dart'; - final GlobalKey key = GlobalKey(); +EmployeeDataSource _employeeDataSource = EmployeeDataSource(); +List _employees = []; +final GlobalKey key = GlobalKey(); + +class PullToRefreshSampleState extends State { + @override + void initState() { + super.initState(); + _employees = getEmployeeData(); + } @override Widget build(BuildContext context) { return Scaffold( - body: SfDataGrid( - key: key, - allowPullToRefresh: true, - 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( + body: SfDataGrid( + key: key, + allowPullToRefresh: true, + source: _employeeDataSource, + columns: [ + GridColumn( + columnName: 'id', + label: Container( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + alignment: Alignment.centerRight, + child: const Text('ID', overflow: TextOverflow.ellipsis), + ), + ), + GridColumn( + columnName: 'name', + label: Container( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + alignment: Alignment.centerLeft, + child: const Text('Name', overflow: TextOverflow.ellipsis), + ), + ), + GridColumn( + columnName: 'designation', + label: Container( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + alignment: Alignment.centerLeft, + child: const Text('Designation', overflow: TextOverflow.ellipsis), + ), + ), + GridColumn( + columnName: 'salary', + label: Container( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + alignment: Alignment.centerRight, + child: const Text('Salary', overflow: TextOverflow.ellipsis), + ), + ), + ], + ), + floatingActionButton: FloatingActionButton( + child: const Icon(Icons.refresh), + onPressed: () { + key.currentState!.refresh(); + }, + ), + ); + } +} + +class EmployeeDataSource extends DataGridSource { + EmployeeDataSource() { + buildDataGridRows(); + } + + List dataGridRows = []; + + @override + List get rows => dataGridRows; + + @override + DataGridRowAdapter? buildRow(DataGridRow row) { + return DataGridRowAdapter( + cells: row.getCells().map((dataGridCell) { + return Container( + alignment: + (dataGridCell.columnName == 'id' || + dataGridCell.columnName == 'salary') + ? Alignment.centerRight + : Alignment.centerLeft, + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Text( + dataGridCell.value.toString(), + overflow: TextOverflow.ellipsis, + ), + ); + }).toList(), + ); + } + + @override + Future handleRefresh() async { + await Future.delayed(const Duration(seconds: 5)); + _addMoreRows(_employees, 15); + buildDataGridRows(); + notifyListeners(); + } + + void buildDataGridRows() { + dataGridRows = _employees + .map( + (dataGridRow) => DataGridRow( + cells: [ + DataGridCell(columnName: 'id', value: dataGridRow.id), + DataGridCell(columnName: 'name', value: dataGridRow.name), + DataGridCell( columnName: 'designation', - label: Container( - padding: EdgeInsets.symmetric(horizontal: 16.0), - alignment: Alignment.centerLeft, - child: Text( - 'Designation', - overflow: TextOverflow.ellipsis, - ))), - GridColumn( + value: dataGridRow.designation, + ), + DataGridCell( columnName: 'salary', - label: Container( - padding: EdgeInsets.symmetric(horizontal: 16.0), - alignment: Alignment.centerRight, - child: Text( - 'Salary', - overflow: TextOverflow.ellipsis, - ))), - ], + value: dataGridRow.salary, + ), + ], + ), + ) + .toList(); + } + + void _addMoreRows(List employees, int count) { + final Random random = Random(); + final startIndex = employees.isNotEmpty ? employees.length : 0, + endIndex = startIndex + count; + for (int i = startIndex; i < endIndex; i++) { + employees.add( + Employee( + 1000 + i, + _names[random.nextInt(_names.length - 1)], + _designation[random.nextInt(_designation.length - 1)], + 10000 + random.nextInt(10000), ), - floatingActionButton: FloatingActionButton( - child: Icon(Icons.refresh), - onPressed: () { - key.currentState!.refresh(); - })); + ); + } } + final List _names = [ + 'Welli', + 'Blonp', + 'Folko', + 'Furip', + 'Folig', + 'Picco', + 'Frans', + 'Warth', + 'Linod', + 'Simop', + 'Merep', + 'Riscu', + 'Seves', + 'Vaffe', + 'Alfki', + ]; + + final List _designation = [ + 'Project Lead', + 'Developer', + 'Manager', + 'Designer', + 'System Analyst', + 'CEO', + ]; +} + {% endhighlight %} {% endtabs %} -Download the demo application from [GitHub](https://github.com/SyncfusionExamples/how-to-perform-pull-to-refresh-programmatically-in-flutter-datatable-sfdatagrid). +> **Reference:** Download the demo application from [GitHub](https://github.com/SyncfusionExamples/how-to-perform-pull-to-refresh-programmatically-in-flutter-datatable-sfdatagrid). ![flutter datagrid shows programmatic refresh indicator](images/pull-to-refresh/flutter-datagrid-programmatic-pull-to-refresh.gif) diff --git a/Flutter/datagrid/right-to-left.md b/Flutter/datagrid/right-to-left.md index 4524d6cfd..092884343 100644 --- a/Flutter/datagrid/right-to-left.md +++ b/Flutter/datagrid/right-to-left.md @@ -9,7 +9,7 @@ documentation: ug # Right to Left (RTL) in Flutter DataGrid (SfDataGrid) -SfDataGrid supports right-to-left rendering. The columns will be rendered based on LTR and RTL direction. +SfDataGrid supports right-to-left (RTL) rendering. When RTL is enabled, columns will be rendered in reverse order, scrollbars will appear on the left side, and text alignment will be mirrored accordingly. ## RTL rendering ways @@ -27,41 +27,48 @@ import 'package:syncfusion_flutter_datagrid/datagrid.dart'; @override Widget build(BuildContext context) { return Directionality( - textDirection: TextDirection.rtl, - child: SfDataGrid( - source: _employeeDataSource, - columnWidthMode: ColumnWidthMode.fill, - columns: [ - 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', - overflow: TextOverflow.ellipsis, - ))), - GridColumn( - columnName: 'salary', - label: Container( - padding: EdgeInsets.all(8.0), - alignment: Alignment.center, - child: Text('Salary'))), - ])); + textDirection: TextDirection.rtl, + child: Scaffold( + body: SfDataGrid( + source: _employeeDataSource, + columnWidthMode: ColumnWidthMode.fill, + columns: [ + 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', overflow: TextOverflow.ellipsis), + ), + ), + GridColumn( + columnName: 'salary', + label: Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.center, + child: Text('Salary'), + ), + ), + ], + ), + ), + ); } {% endhighlight %} @@ -69,19 +76,19 @@ import 'package:syncfusion_flutter_datagrid/datagrid.dart'; ### Changing the locale to RTL languages -To change the Datagrid rendering direction from right to left, change the [locale](https://api.flutter.dev/flutter/material/MaterialApp/locale.html) to any of the RTL languages such as Arabic, Persian, Hebrew, Pashto, and Urdu. +Change the [locale](https://api.flutter.dev/flutter/material/MaterialApp/locale.html) property of [MaterialApp](https://api.flutter.dev/flutter/material/MaterialApp-class.html) to an RTL language such as Arabic, Persian, Hebrew, Pashto, or Urdu to enable RTL rendering. -To use `flutter_localizations`, add the package as a dependency to `pubspec.yaml` file. +> **Note:** The `flutter_localizations` package is required. Add it to your `pubspec.yaml` file: +> +> ```dart +> dependencies: +> flutter_localizations: +> sdk: flutter +> ``` +> +> Then run `flutter pub get` to download the package. -{% highlight dart %} - -dependencies: -flutter_localizations: - sdk: flutter - -{% endhighlight %} - -Then, import the `flutter_localizations` library, specify [localizationsDelegates](https://api.flutter.dev/flutter/widgets/LocalizationsDelegate-class.html) and `supportedLocales` for `MaterialApp`. +Import the `flutter_localizations` library and configure [localizationsDelegates](https://api.flutter.dev/flutter/widgets/LocalizationsDelegate-class.html) and `supportedLocales` in your `MaterialApp`. {% tabs %} {% highlight Dart %} @@ -92,50 +99,61 @@ import 'package:flutter_localizations/flutter_localizations.dart'; @override Widget build(BuildContext context) { return MaterialApp( - localizationsDelegates: [ - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - ], - supportedLocales: [ - Locale('en'), - Locale('ar'), - // ... other locales the app supports - ], - locale: Locale('ar'), - home: SfDataGrid( - source: _employeeDataSource, - columnWidthMode: ColumnWidthMode.fill, - columns: [ - 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', - overflow: TextOverflow.ellipsis, - ))), - GridColumn( - columnName: 'salary', - label: Container( - padding: EdgeInsets.all(8.0), - alignment: Alignment.center, - child: Text('Salary'))), - ])); + localizationsDelegates: [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ], + supportedLocales: [ + Locale('en'), + Locale('ar'), + Locale('fa'), + Locale('he'), + Locale('ps'), + Locale('ur'), + ], + locale: Locale('ar'), + home: Scaffold( + appBar: AppBar(title: Text('RTL DataGrid')), + body: SfDataGrid( + source: _employeeDataSource, + columnWidthMode: ColumnWidthMode.fill, + columns: [ + 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', overflow: TextOverflow.ellipsis), + ), + ), + GridColumn( + columnName: 'salary', + label: Container( + padding: EdgeInsets.all(8.0), + alignment: Alignment.center, + child: Text('Salary'), + ), + ), + ], + ), + ), + ); } {% endhighlight %} diff --git a/Flutter/datagrid/row-height-customization.md b/Flutter/datagrid/row-height-customization.md index 4e58cb3d9..68833e91d 100644 --- a/Flutter/datagrid/row-height-customization.md +++ b/Flutter/datagrid/row-height-customization.md @@ -128,13 +128,13 @@ The row height can be autofit based on its content in the `SfDataGrid.onQueryRow {% endhighlight %} {% endtabs %} -![flutter datagrid shows autofit the row height based on content](images/row-height-customization/flutter-datagrid-autofit-rows.png) +![flutter datagrid shows auto-fitting the row height based on content](images/row-height-customization/flutter-datagrid-autofit-rows.png) -The `RowHeightDetails.getIntrinsicRowHeight` method provides some properties to customize the autofit calculation, +The [RowHeightDetails.getIntrinsicRowHeight](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/RowHeightDetails/getIntrinsicRowHeight.html) method provides some properties to customize the autofit calculation: -* `excludeColumns` – By default, the `getIntrinsicRowHeight` method calculates the row height based on all columns. To skip the specific columns from the row height calculation, add that column's [GridColumn.columnName](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn/columnName.html) to the `excludeColumns` collection. +* `excludedColumns` – By default, the `getIntrinsicRowHeight` method calculates the row height based on all columns. To skip specific columns from the row height calculation, add that column's [GridColumn.columnName](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn/columnName.html) to the `excludedColumns` collection. -* `canIncludeHiddenColumns` – The hidden columns ([GridColumn.visible](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn/visible.html) is false) can also be considered for the row height calculation by setting the `canIncludeHiddenColumns` as true. +* `canIncludeHiddenColumns` – The hidden columns ([GridColumn.visible](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/GridColumn/visible.html) is `false`) can also be considered for the row height calculation by setting `canIncludeHiddenColumns` to `true`. {% tabs %} {% highlight dart %} @@ -334,25 +334,24 @@ class CustomColumnSizer extends ColumnSizer { {% endhighlight %} {% endtabs %} -**NOTE** - Download the demo application from [GitHub](https://github.com/SyncfusionExamples/how-to-fit-the-rows-based-on-the-different-text-style-in-Flutter-DataTable-sfdatagrid). +> **Note:** The `CustomColumnSizer` is a custom class that should be added to your dart file. You can download the complete demo application from [GitHub](https://github.com/SyncfusionExamples/how-to-fit-the-rows-based-on-the-different-text-style-in-Flutter-DataTable-sfdatagrid). -![flutter datagrid shows autofit the row height based on different text style](images/row-height-customization/flutter-datagrid-autofit-textstyle-customization.png) +![flutter datagrid shows auto-fitting the row height based on different text style](images/row-height-customization/flutter-datagrid-autofit-textstyle-customization.png) ## Fit the row based on the formatted value -By default, the cell height is calculated based on the `DataGridCell.value` property. To autofit the cell height based on the displayed formatted value (this is, DateFormat and NumberFormat), simply override the `computeCellHeight` method and return the super method with the required `cellValue.` +By default, the cell height is calculated based on the `DataGridCell.value` property. To autofit the cell height based on the displayed formatted value (such as DateFormat and NumberFormat), simply override the `computeCellHeight` method and return the super method with the required `cellValue`. -To use `intl`, add the package as a dependency to the `pubspec.yaml` file. +To use date and number formatting, add the `intl` package as a dependency to the `pubspec.yaml` file. {% highlight dart %} dependencies: - intl: ^0.17.0 + intl: ^0.19.0 {% endhighlight %} -Import the `intl` library, to use the date and number format. +Import the required packages: {% tabs %} {% highlight dart %} @@ -484,15 +483,16 @@ class CustomColumnSizer extends ColumnSizer { {% endhighlight %} {% endtabs %} -**NOTE** - Download the demo application from [GitHub](https://github.com/SyncfusionExamples/how-to-fit-the-rows-based-on-the-formatted-value-in-Flutter-datatable-sfdatagrid). +> **Note:** Download the complete demo application from [GitHub](https://github.com/SyncfusionExamples/how-to-fit-the-rows-based-on-the-formatted-value-in-Flutter-datatable-sfdatagrid). -![flutter datagrid shows autofit the row height based on formatted cell value](images/row-height-customization/flutter-datagrid-formatted-cellvalue.png) +![flutter datagrid shows auto-fitting the row height based on formatted cell value](images/row-height-customization/flutter-datagrid-formatted-cellvalue.png) ## Set height for the header row [SfDataGrid](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid-class.html) allows you to customize the height of the header row by using the [headerRowHeight](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/headerRowHeight.html) property. +> **Note:** The default value of `headerRowHeight` is `49.0`. You can set any double value to customize the header row height according to your requirements. + {% tabs %} {% highlight dart %} @@ -552,6 +552,8 @@ class CustomColumnSizer extends ColumnSizer { You can customize the height of the grid rows in `SfDataGrid` by using the [rowHeight](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/rowHeight.html) property. +> **Note:** The default value of `rowHeight` is `49.0`. Use this property to set a uniform height for all data rows (excluding the header row). For variable heights based on content, use the `onQueryRowHeight` callback instead. + {% tabs %} {% highlight Dart %} @@ -613,18 +615,19 @@ The `SfDataGrid` allows you to update or refresh a specific row and its height w Refresh a specific row and its height by using the [DataGridController.refreshRow](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/refreshRow.html) method. This method has the following two arguments: -* **rowIndex**- Specify the required row index which is required to refresh. If you specify this, the data alone will be refreshed for a row. +* **rowIndex** - Specify the row index to refresh. If you specify this alone, only the data will be refreshed for that row. -* **recalculateRowHeight** - Decides whether a height of a row should be refreshed along with the data. +* **recalculateRowHeight** - Determines whether the row height should be recalculated along with the data refresh. -If you call the `refreshRow` method, the `onQueryRowHeight` callback will be called for that specific row. So, auto-calculation of height can be recalculated for that row. +When you call the `refreshRow` method, the `onQueryRowHeight` callback will be invoked for that specific row, allowing auto-height calculation to be recalculated. -In the below example, row data is updated when the `refreshRow` is called in the `onPressed` callback of the `TextButton.` +> **Note:** When calling `refreshRow`, ensure the rowIndex is within the valid range (0 to dataGridRows.length - 1). Calling with an out-of-bounds rowIndex may not refresh the intended row. Use `recalculateRowHeight: true` to recalculate row heights based on updated content. + +In the following example, row data is updated when `refreshRow` is called in the `onPressed` callback of the `TextButton`: {% tabs %} {% highlight Dart %} - List _employees = []; late EmployeeDataSource _employeeDataSource; final DataGridController _controller = DataGridController(); List _employees = []; @@ -755,12 +758,11 @@ class EmployeeDataSource extends DataGridSource { {% endhighlight %} {% endtabs %} -In the following example, the row data is refreshed along with its row height when the `refreshRow` is called in the `onPressed` callback of the `TextButton.` +In the following example, the row data is refreshed along with its row height when `refreshRow` is called with `recalculateRowHeight: true` in the `onPressed` callback of the `TextButton`: {% tabs %} {% highlight Dart %} - List _employees = []; late EmployeeDataSource _employeeDataSource; final DataGridController _controller = DataGridController(); List _employees = []; @@ -775,74 +777,129 @@ In the following example, the row data is refreshed along with its row height wh @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - title: const Text('Syncfusion Flutter DataGrid'), - ), - body: Column(children: [ + appBar: AppBar(title: const Text('Syncfusion Flutter DataGrid')), + body: Column( + children: [ TextButton( - child: const Text('Update cell value'), - onPressed: () { - _employees[0].id = 1010; - _employees[0].name = 'Maria Anders'; - _employees[0].designation = 'Sales Representative'; - _employees[0].salary = 25000; - _controller.refreshRow(0, recalculateRowHeight: true); - _employeeDataSource.buildDataGridSource(_employees); - _employeeDataSource.updateDataGridSource(); - }), + child: const Text('Update cell value'), + onPressed: () { + _employees[0].id = 1010; + _employees[0].name = 'Maria Anders'; + _employees[0].designation = 'Sales Representative'; + _employees[0].salary = 25000; + _controller.refreshRow(0, recalculateRowHeight: true); + _employeeDataSource.buildDataGridSource(_employees); + _employeeDataSource.updateDataGridSource(); + }, + ), Expanded( - child: SfDataGrid( - source: _employeeDataSource, - controller: _controller, - columnSizer: _columnSizer, - columnWidthMode: ColumnWidthMode.auto, - onQueryRowHeight: (RowHeightDetails details) { - if (details.rowIndex == 0) { - return 100.0; - } - - return 50.0; - }, - columns: [ + child: SfDataGrid( + source: _employeeDataSource, + controller: _controller, + columnWidthMode: ColumnWidthMode.auto, + onQueryRowHeight: (RowHeightDetails details) { + if (details.rowIndex == 0) { + return 100.0; + } + + return 50.0; + }, + columns: [ GridColumn( - columnName: 'id', - label: Container( - padding: EdgeInsets.symmetric(horizontal: 16.0), - alignment: Alignment.centerRight, - child: Text( - 'ID', - overflow: TextOverflow.ellipsis, - ))), + 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, - ))), + 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, - ))), + 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, - ))), - ])) - ])); + columnName: 'salary', + label: Container( + padding: EdgeInsets.symmetric(horizontal: 16.0), + alignment: Alignment.centerRight, + child: Text('Salary', overflow: TextOverflow.ellipsis), + ), + ), + ], + ), + ), + ], + ), + ); + } + +class EmployeeDataSource extends DataGridSource { + EmployeeDataSource({required List employees}) { + buildDataGridSource(employees); + } + + void buildDataGridSource(List employees) { + dataGridRows = employees + .map( + (dataGridRow) => DataGridRow( + cells: [ + DataGridCell(columnName: 'id', value: dataGridRow.id), + DataGridCell(columnName: 'name', value: dataGridRow.name), + DataGridCell( + columnName: 'designation', + value: dataGridRow.designation, + ), + DataGridCell( + columnName: 'salary', + value: dataGridRow.salary, + ), + ], + ), + ) + .toList(); } + List dataGridRows = []; + + @override + List get rows => dataGridRows; + + @override + DataGridRowAdapter? buildRow(DataGridRow row) { + return DataGridRowAdapter( + cells: row.getCells().map((dataGridCell) { + return Container( + 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, + ), + ); + }).toList(), + ); + } + + void updateDataGridSource() { + notifyListeners(); + } +} + {% endhighlight %} {% endtabs %} diff --git a/Flutter/datagrid/scrolling.md b/Flutter/datagrid/scrolling.md index 4fec6a5fd..351711f07 100644 --- a/Flutter/datagrid/scrolling.md +++ b/Flutter/datagrid/scrolling.md @@ -13,9 +13,9 @@ SfDataGrid provides support to scroll the content in both horizontal and vertica ## Show Scrollbars always -You can show horizontal and vertical scrollbars always by using the [SfDataGrid.isScrollbarAlwaysShown](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/isScrollbarAlwaysShown.html) property. When the `isScrollbarAlwaysShown` is set to false, the scrollbar will be shown during scrolling and will fade out otherwise. When it is true, the scrollbar will always be visible and never fade out even after the scrolling. +You can show horizontal and vertical scrollbars always by using the [SfDataGrid.isScrollbarAlwaysShown](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/isScrollbarAlwaysShown.html) property. When the `isScrollbarAlwaysShown` is set to `false`, the scrollbar will be shown during scrolling and will fade out otherwise. When it is `true`, the scrollbar will always be visible and never fade out even after scrolling. -N> The default value of `isScrollbarAlwaysShown` is false. +> **Note:** The default value of `isScrollbarAlwaysShown` is `false`. This ensures scrollbars appear only during active scrolling for a cleaner UI. {% tabs %} {% highlight Dart %} @@ -71,9 +71,9 @@ N> The default value of `isScrollbarAlwaysShown` is false. ## Change scrollbars visibility -You can control the visibility of horizontal and vertical scrollbars in the DataGrid by setting the [SfDataGrid.showVerticalScrollbar](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/showVerticalScrollbar.html) and [SfDataGrid.showHorizontalScrollbar](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/showHorizontalScrollbar.html) properties. To disable the default scrollbar of the `SingleChildScrollView`, wrap the `ScrollConfiguration` as the parent for the `SfDataGrid` and set the scrollbars to false. +You can control the visibility of horizontal and vertical scrollbars in the DataGrid by setting the [SfDataGrid.showVerticalScrollbar](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/showVerticalScrollbar.html) and [SfDataGrid.showHorizontalScrollbar](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/showHorizontalScrollbar.html) properties. To disable the default scrollbar of the `SingleChildScrollView`, wrap the `ScrollConfiguration` as the parent for the `SfDataGrid` and set the scrollbars to `false`. This prevents duplicate scrollbars from appearing. -N> The default value of `showVerticalScrollbar` and `showHorizontalScrollbar` is true. +> **Note:** The default value of `showVerticalScrollbar` and `showHorizontalScrollbar` is `true`. Setting these to `false` disables only the DataGrid's internal scrollbars. The following code snippets demonstrate how to hide the scrollbars in the DataGrid: @@ -136,7 +136,7 @@ The following code snippets demonstrate how to hide the scrollbars in the DataGr SfDataGrid allows you to set the [ScrollPhysics](https://api.flutter.dev/flutter/widgets/ScrollPhysics-class.html) for horizontal and vertical scrollbars to control how the scroll view should respond to user input by using [horizontalScrollPhysics](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/horizontalScrollPhysics.html) and [verticalScrollPhysics](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/verticalScrollPhysics.html) properties respectively. -N> The default values of `horizontalScrollPhysics` and `verticalScrollPhysics` properties are `AlwaysScrollableScrollPhysics()`. +> **Note:** The default values of `horizontalScrollPhysics` and `verticalScrollPhysics` properties are `AlwaysScrollableScrollPhysics()`. The following example shows how to disable the horizontal and vertical scrolling by setting `NeverScrollableScrollPhysics()`. @@ -199,9 +199,11 @@ The Flutter DataTable provides support to scroll to a particular row and column ### Scroll to cell -Scroll programmatically to a particular cell can be achieved by passing the row and column index in the `scrollToCell` method. SfDataGrid allows to enable or disable the scrolling animation by passing `true` to the `canAnimate` parameter in the `scrollToCell` method. +Scroll programmatically to a particular cell by passing the row and column index to the [DataGridController.scrollToCell](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/scrollToCell.html) method. SfDataGrid allows you to enable or disable the scrolling animation by passing `true` to the `canAnimate` parameter. -N> The default value of `canAnimate` is `false`. +> **Note:** +>- The default value of `canAnimate` is `false`. If you specify a rowIndex or columnIndex that exceeds the valid range, the scrolling will not occur. +>- Ensure you have imported the required package: `import 'package:syncfusion_flutter_datagrid/datagrid.dart';` {% tabs %} {% highlight Dart %} @@ -272,9 +274,9 @@ N> The default value of `canAnimate` is `false`. ### Scroll to row -Scroll programmatically to a particular row by passing the row index in the `scrollToRow` method. SfDataGrid allows to enable or disable the scrolling animation by passing `true` to the `canAnimate` parameter in the `scrollToRow` method. +Scroll programmatically to a particular row by passing the row index to the [DataGridController.scrollToRow](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/scrollToRow.html) method. SfDataGrid allows you to enable or disable the scrolling animation by passing `true` to the `canAnimate` parameter. -N> The default value of `canAnimate` is `false`. +> **Note:** The default value of `canAnimate` is `false`. If the specified rowIndex exceeds the total number of rows, the scrolling will not occur. {% tabs %} {% highlight Dart %} @@ -343,9 +345,9 @@ N> The default value of `canAnimate` is `false`. ### Scroll to column -Scroll programmatically to a particular column by passing the column index in the `scrollToColumn` method. SfDataGrid allows to enable or disable the scrolling animation by passing `true` to the `canAnimate` parameter in the `scrollToColumn` method. +Scroll programmatically to a particular column by passing the column index to the [DataGridController.scrollToColumn](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/scrollToColumn.html) method. SfDataGrid allows you to enable or disable the scrolling animation by passing `true` to the `canAnimate` parameter. -N> The default value of `canAnimate` is `false`. +> **Note:** The default value of `canAnimate` is `false`. If the specified columnIndex exceeds the total number of columns, the scrolling will not occur. {% tabs %} {% highlight Dart %} @@ -416,14 +418,14 @@ N> The default value of `canAnimate` is `false`. ### Scroll to the specific position -The `SfDataGrid` allows positioning of the scrolled row or column in view programmatically by passing the `DataGridScrollPosition` to `rowPosition` and `columnPosition` arguments respectively in `scrollToCell` and `position` argument of the `scrollToRow` and `scrollToColumn` methods. The following are the four types of positions available. +The `SfDataGrid` allows positioning of the scrolled row or column in view programmatically by passing the [DataGridScrollPosition](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridScrollPosition.html) to `rowPosition` and `columnPosition` arguments respectively in `scrollToCell` and `position` argument of the `scrollToRow` and `scrollToColumn` methods. The following are the four types of positions available: -`makeVisible`: Scroll to make a specified row/column visible in Datagrid. If the specified row/column is already in view, scrolling will not occur. -`start`: Scroll to make the row/column positioned at the start of the Datagrid. -`center`: Scroll to make the row/column positioned at the center of the Datagrid. -`end`: Scroll to make the row/column positioned at the end of the Datagrid. +* `makeVisible` - Display the specified row/column if it is not already visible. If already in view, no scrolling occurs. +* `start` - Position the row/column at the start of the DataGrid. +* `center` - Position the row/column at the center of the DataGrid. +* `end` - Position the row/column at the end of the DataGrid. -N> The default value of `DataGridScrollPosition` is `Start`. +> **Note:** The default value of `DataGridScrollPosition` is `start`. {% tabs %} {% highlight Dart %} @@ -495,9 +497,9 @@ N> The default value of `DataGridScrollPosition` is `Start`. ### Scroll to the vertical offset -The Flutter DataTable supports scrolling programmatically to a particular vertical offset by passing the offset value to the `scrollToVerticalOffset` method. Also, it allows enabling the scrolling animation by passing `true` to the `canAnimate` parameter in the `scrollToVerticalOffset` method. +The Flutter DataTable supports scrolling programmatically to a particular vertical offset by passing the offset value to the [DataGridController.scrollToVerticalOffset](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/scrollToVerticalOffset.html) method. You can enable the scrolling animation by passing `true` to the `canAnimate` parameter. -N> The default value of `canAnimate` is `false`. +> **NOTE:** The default value of `canAnimate` is `false`. The offset value should be non-negative and not exceed the maximum scrollable extent. {% tabs %} {% highlight Dart %} @@ -566,9 +568,9 @@ N> The default value of `canAnimate` is `false`. ### Scroll to the horizontal offset -The Flutter DataTable supports scrolling programmatically to a particular horizontal offset by passing the offset value to the `scrollToHorizontalOffset` method. Also, it allows enabling the scrolling animation by passing `true` to the `canAnimate` parameter in the `scrollToHorizontalOffset` method. +The Flutter DataTable supports scrolling programmatically to a particular horizontal offset by passing the offset value to the [DataGridController.scrollToHorizontalOffset](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/scrollToHorizontalOffset.html) method. You can enable the scrolling animation by passing `true` to the `canAnimate` parameter. -N> The default value of `canAnimate` is `false`. +> **Note:** The default value of `canAnimate` is `false`. The offset value should be non-negative and not exceed the maximum scrollable extent. {% tabs %} {% highlight Dart %} @@ -635,21 +637,25 @@ N> The default value of `canAnimate` is `false`. {% endhighlight %} {% endtabs %} -N> The vertical and horizontal scrolled offset can be retrieved by using `DataGridController.verticalOffset` and `DataGridController.horizontalOffset` properties. +> **Note:** The vertical and horizontal scroll offsets can be retrieved using the [DataGridController.verticalOffset](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/verticalOffset.html) and [DataGridController.horizontalOffset](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/horizontalOffset.html) properties respectively. -## Listen the scroll changes +## Listen to scroll changes -Listen to the vertical and horizontal scroll changes by using the [verticalScrollController](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/verticalScrollController.html) and the [horizontalScrollController](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/horizontalScrollController.html) properties respectively. Set the listener in the `verticalScrollController` and the `horizontalScrollController` using the `addListener` method. By subscribing to this listener, the subscribed method in the sample level will be called on vertical or horizontal scrolling. +Listen to the vertical and horizontal scroll changes by using the [verticalScrollController](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/verticalScrollController.html) and [horizontalScrollController](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/horizontalScrollController.html) properties respectively. Set listeners on these controllers using the `addListener` method to receive notifications when scrolling occurs. -The following example demonstrates how to load more rows when vertical scrolling reaches 70% of the vertical maxScrollExtent, +> **Note:** The `intl` package is required for number formatting. Add `intl: ^0.19.0` to your `pubspec.yaml` dependencies. + +The following example demonstrates how to load more rows when vertical scrolling reaches 70% of the maximum scroll extent: {% tabs %} {% highlight Dart %} +import 'dart:math'; import 'package:intl/intl.dart'; +import 'package:syncfusion_flutter_datagrid/datagrid.dart'; late EmployeeDataSource _employeeDataSource; - late ScrollController verticalScrollController; + late ScrollController _verticalScrollController; void verticalListener() { if (_verticalScrollController.position.pixels >= @@ -748,14 +754,15 @@ class _EmployeeDataSource extends DataGridSource { {% endhighlight %} {% endtabs %} -**NOTE** - Download the demo application from [GitHub](https://github.com/SyncfusionExamples/how-to-load-data-lazily-when-scrolling-reaches-70-in-flutter-datatable-sfdatagrid). +> **Note:** Download the complete demo application from [GitHub](https://github.com/SyncfusionExamples/how-to-load-data-lazily-when-scrolling-reaches-70-in-flutter-datatable-sfdatagrid). ## Increase row cache limit -By default, rows are generated based on the viewport size, and these rows are reused while scrolling. Set the [SfDataGrid.rowsCacheExtent](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/rowsCacheExtent.html) property to avoid the visible changes caused by re-using. For example, if you show the checkbox in a column without setting the rows using this property, checkbox state changes with animation can be seen when vertical scrolling is performed. +By default, rows are generated based on the viewport size, and these rows are reused while scrolling. Set the [SfDataGrid.rowsCacheExtent](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/rowsCacheExtent.html) property to avoid visual artifacts caused by row reuse. For example, if you display a checkbox in a column, without setting this property, you may see checkbox state animation changes during vertical scrolling. -The `rowsCacheExtent` property will create the additional rows internally with the existing visible rows, which are already allocated based on viewport size. So, the number of rows that will be reused will increase. +The `rowsCacheExtent` property creates additional rows internally alongside the visible rows allocated based on viewport size, increasing the number of rows available for reuse. + +> **Note:** Increasing `rowsCacheExtent` improves visual consistency but may impact performance with large datasets. Use this property judiciously based on your application's performance requirements. {% tabs %} {% highlight Dart %} @@ -821,8 +828,7 @@ The `rowsCacheExtent` property will create the additional rows internally with t If the height or width of the DataGrid is infinity, then DataGrid sets its height or width to 300 by default. Users can set the height or width based on the number of rows or columns available in DataGrid by using the [shrinkWrapRows](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/shrinkWrapRows.html) or [shrinkWrapColumns](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/shrinkWrapColumns.html) property, respectively. ->**NOTE** -Shrink wrapping is significantly more expensive than setting the height and width manually. +> **Note:** Shrink wrapping is significantly more expensive than setting the height and width manually. Use this property only when the number of rows and columns is small. {% tabs %} {% highlight Dart %} @@ -887,7 +893,7 @@ late EmployeeDataSource _employeeDataSource; ## Retrieve the indices of visible rows and columns -In the SfDataGrid, you can obtain the starting and ending indices of the visible rows using the [DataGridController.getVisibleRowStartIndex](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/getVisibleRowStartIndex.html) and [DataGridController.getVisibleRowEndIndex](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/getVisibleRowEndIndex.html) methods, respectively, by specifying the needed `RowRegion`. Similarly, for the visible columns, you can retrieve the starting and ending indices using the [DataGridController.getVisibleColumnStartIndex](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/getVisibleColumnStartIndex.html) and [DataGridController.getVisibleColumnEndIndex](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/getVisibleColumnEndIndex.html) methods, respectively. +In the SfDataGrid, you can obtain the starting and ending indices of the visible rows using the [DataGridController.getVisibleRowStartIndex](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/getVisibleRowStartIndex.html) and [DataGridController.getVisibleRowEndIndex](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/getVisibleRowEndIndex.html) methods, respectively, by specifying the needed [RowRegion](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/RowRegion.html). The possible values are `header`, `body`, and `footer`. Similarly, for the visible columns, you can retrieve the starting and ending indices using the [DataGridController.getVisibleColumnStartIndex](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/getVisibleColumnStartIndex.html) and [DataGridController.getVisibleColumnEndIndex](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/getVisibleColumnEndIndex.html) methods, respectively. {% tabs %} {% highlight Dart %} @@ -956,22 +962,24 @@ In the SfDataGrid, you can obtain the starting and ending indices of the visible {% endtabs %} ## Set the scroll offset on initial loading -SfDataGrid allows you to set the scroll offset upon initial loading for both horizontal and vertical scroll bars. This can be achieved by assigning the offset value to the [initialScrollOffset](https://api.flutter.dev/flutter/widgets/ScrollController/initialScrollOffset.html) property of the [ScrollController](https://api.flutter.dev/flutter/widgets/ScrollController-class.html) for the needed vertical or horizontal controller. + +SfDataGrid allows you to set the scroll offset upon initial loading for both horizontal and vertical scrollbars. This is achieved by assigning the offset value to the [initialScrollOffset](https://api.flutter.dev/flutter/widgets/ScrollController/initialScrollOffset.html) property of the [ScrollController](https://api.flutter.dev/flutter/widgets/ScrollController-class.html) for the required vertical or horizontal controller. + +> **Note:** Ensure you have imported the required package: `import 'package:syncfusion_flutter_datagrid/datagrid.dart';` {% tabs %} {% highlight Dart %} -import 'package:syncfusion_flutter_datagrid/datagrid.dart'; - late EmployeeDataSource _employeeDataSource; late ScrollController _verticalScrollController; late ScrollController _horizontalScrollController; + late List employees; @override void initState() { super.initState(); employees = getEmployeeData(); - employeeDataSource = EmployeeDataSource(employeeData: employees); + _employeeDataSource = EmployeeDataSource(employeeData: employees); _verticalScrollController = ScrollController( initialScrollOffset: 500, ); diff --git a/Flutter/datagrid/selection.md b/Flutter/datagrid/selection.md index 1ef0b3495..00ece32d4 100644 --- a/Flutter/datagrid/selection.md +++ b/Flutter/datagrid/selection.md @@ -10,9 +10,11 @@ documentation: ug 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](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/selectionMode.html) property of the SfDataGrid to a value other than `none`. SfDataGrid has different selection modes to perform the selection operation as follows. +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](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/selectionMode.html) 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. -N> The [rows](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/rows.html) property must be initialized in the [source](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/source.html). The `rows` is the collection of `DataGridRow` to populate the rows in DataGrid. +> **Note:** +>- The [rows](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridSource/rows.html) property must be initialized in the [source](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/source.html). The `rows` is the collection of `DataGridRow` to populate the rows in DataGrid. +>- Import the [SelectionMode](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SelectionMode.html) enum from the `syncfusion_flutter_datagrid` package to use different selection modes in your application. ## Selection modes @@ -160,9 +162,9 @@ It allows you to select only one row. For example, you have selected a row. Now ### 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. +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. -While using `multiple`, you can select multiple rows by pressing the key modifiers Shift + Down and Shift + Up. +When using `multiple`, you can select multiple rows by pressing the key modifiers Shift + Down and Shift + Up. {% tabs %} {% highlight Dart %} @@ -218,7 +220,61 @@ While using `multiple`, you can select multiple rows by pressing the key modifie ![flutter datagrid shows multiple row selection](images/selection/flutter-datagrid-multiple-selection.png) -N> When the `selectionMode` is `multiple`, 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. +> **Note:** When the `selectionMode` is `multiple`, 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. + +{% tabs %} +{% highlight Dart %} + + @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, + ), + ); + } + +{% endhighlight %} +{% endtabs %} ### Disable selection @@ -278,11 +334,13 @@ The selection can be disabled by setting the `selectionMode` property as `none`. Selection on a particular row can be disabled by handling the [onCurrentCellActivating](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/onCurrentCellActivating.html) callback. - N> You cannot select the header row of SfDataGrid. +> **Note:** You cannot select the header row of SfDataGrid. ## Getting selected rows -Get the information of the selected rows by using the [controller](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/controller.html) property. Create an instance of the [DataGridController](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController-class.html) and set it to controller property. The [selectedRow](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/selectedRow.html) property returns the selected DataGridRow and the [selectedIndex](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/selectedIndex.html) property returns the index of the [selectedRow](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/selectedRow.html) in SfDataGrid. The [selectedRow](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/selectedRow.html) denotes the last selected row in multiple selections. +Get the information of the selected rows by using the [controller](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/SfDataGrid/controller.html) property. Create an instance of the [DataGridController](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController-class.html) and set it to the controller property. The [selectedRow](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/selectedRow.html) property returns the selected DataGridRow and the [selectedIndex](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/selectedIndex.html) property returns the index of the [selectedRow](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/selectedRow.html) in SfDataGrid. The [selectedRow](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController/selectedRow.html) denotes the last selected row in multiple selections. + +> **Note:** [DataGridController](https://pub.dev/documentation/syncfusion_flutter_datagrid/latest/datagrid/DataGridController-class.html) 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. {% tabs %} {% highlight Dart %} @@ -358,13 +416,11 @@ Get the information of the selected rows by using the [controller](https://pub.d {% endhighlight %} {% endtabs %} -N> DataGridController objects are expected to be long-lived, not re-created with each build. - ## Programmatic selection -When `selectionMode` is set to a value other than `none`, the selected rows from the code by setting the `DataGridController.selectedIndex`, `DataGridController.selectedRow`, or `DataGridController.selectedRows` property based on the selection mode. +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`, programmatically select a row in two ways either by setting the row index to the `DataGridController.selectedIndex` property, or by setting the `DataGridRow` to be selected to the `DataGridController.selectedRow` property +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`, @@ -862,7 +918,7 @@ The following code example shows how to clear selection when the `selectionMode` {% endhighlight %} {% endtabs %} -N> Selected rows and selections will be cleared whenever the `dataSource` is changed at runtime. +> **Note:** Selected rows and selections will be cleared whenever the `dataSource` is changed at runtime. ## Keyboard behavior @@ -1025,13 +1081,13 @@ If the current cell is in edit mode, call the _signaturePadKey = GlobalKey(); - return Scaffold( - body: Column( - children: [ - Container( - child: SfSignaturePad( - key: _signaturePadKey, - backgroundColor: Colors.grey[200], +{% highlight dart %} + +import 'dart:ui' as ui; +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_signaturepad/signaturepad.dart'; + +class SignaturePadExample extends StatefulWidget { + @override + _SignaturePadExampleState createState() => _SignaturePadExampleState(); +} + +class _SignaturePadExampleState extends State { + final GlobalKey _signaturePadKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Column( + children: [ + Container( + child: SfSignaturePad( + key: _signaturePadKey, + backgroundColor: Colors.grey[200], + ), + height: 200, + width: 300, ), - height: 200, - width: 300, - ), - RaisedButton( - child: Text("Save As Image"), + ElevatedButton( + child: const Text('Save As Image'), onPressed: () async { - ui.Image image = - await _signaturePadKey.currentState!.toImage(); - }), - ], - ), - ); + final image = await _signaturePadKey.currentState!.toImage(); + }, + ), + ], + ), + ); + } } {% endhighlight %} @@ -217,47 +251,55 @@ Widget build(BuildContext context) { You can save the signature drawn in the SignaturePad as an image using the [`renderToContext2D`](https://pub.dev/documentation/syncfusion_flutter_signaturepad/latest/signaturepad/SfSignaturePadState/renderToContext2D.html) method as shown in the code snippet below. Since this [`renderToContext2D()`](https://pub.dev/documentation/syncfusion_flutter_signaturepad/latest/signaturepad/SfSignaturePadState/renderToContext2D.html) method is defined in the state object of SignaturePad, you have to use a global key assigned to the SignaturePad instance to call this method. {% tabs %} -{% highlight Dart %} - -@override -Widget build(BuildContext context) { - GlobalKey _signaturePadKey = GlobalKey(); - return Scaffold( - body: Column( - children: [ - Container( - child: SfSignaturePad( - key: _signaturePadKey, - backgroundColor: Colors.grey[200], +{% highlight dart %} + +import 'dart:async'; +import 'dart:html' as html; +import 'dart:typed_data'; +import 'dart:ui' as ui; +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_signaturepad/signaturepad.dart'; + +class SignaturePadExample extends StatefulWidget { + @override + _SignaturePadExampleState createState() => _SignaturePadExampleState(); +} + +class _SignaturePadExampleState extends State { + final GlobalKey _signaturePadKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Column( + children: [ + Container( + child: SfSignaturePad( + key: _signaturePadKey, + backgroundColor: Colors.grey[200], + ), + height: 200, + width: 300, ), - height: 200, - width: 300, - ), - RaisedButton( - child: Text("Save As Image"), + ElevatedButton( + child: const Text('Save As Image'), onPressed: () async { - - //Get a html canvas context. - final canvas = html.CanvasElement(width: 500, height: 500); - final context = canvas.context2D; - - //Get the signature in the canvas context. - _signaturePadKey.currentState!.renderToContext2D(context); - - //Get the image from the canvas context - final blob = await canvas.toBlob('image/jpeg', 1.0); - - //Save the image as Uint8List to use it in local device. - final completer = Completer(); - final reader = html.FileReader(); - reader.readAsArrayBuffer(blob); - reader.onLoad.listen((_) => completer.complete(reader.result)); - Uint8List imageData = await completer.future; - - }), - ], - ), - ); + final canvas = html.CanvasElement(width: 500, height: 500); + final context = canvas.context2D; + _signaturePadKey.currentState!.renderToContext2D(context); + + final blob = await canvas.toBlob('image/jpeg', 1.0); + final completer = Completer(); + final reader = html.FileReader(); + reader.readAsArrayBuffer(blob); + reader.onLoad.listen((_) => completer.complete(reader.result)); + final imageData = await completer.future as Uint8List; + }, + ), + ], + ), + ); + } } {% endhighlight %} @@ -270,33 +312,43 @@ N> Since Flutter uses two separate default web renderers, here we have two diffe You can clear the signature drawn in the SignaturePad using the [`clear()`](https://pub.dev/documentation/syncfusion_flutter_signaturepad/latest/signaturepad/SfSignaturePadState/clear.html) method as shown in the code snippet below. Since this [`clear()`](https://pub.dev/documentation/syncfusion_flutter_signaturepad/latest/signaturepad/SfSignaturePadState/clear.html) method is defined in the state object of SignaturePad, you have to use a global key assigned to the SignaturePad instance to call this method. {% tabs %} -{% highlight Dart %} - -@override -Widget build(BuildContext context) { - GlobalKey _signaturePadKey = GlobalKey(); - return Scaffold( - body: Column( - children: [ - Container( - child: SfSignaturePad( - key: _signaturePadKey, - backgroundColor: Colors.grey[200], - ), - height: 200, - width: 300, - ), - RaisedButton( - child: Text("Save As Image"), - onPressed: () async { - ui.Image image = - _signaturePadKey.currentState!.clear(); - }), - ], - ), - ); +{% highlight dart %} + +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_signaturepad/signaturepad.dart'; + +class SignaturePadExample extends StatefulWidget { + @override + _SignaturePadExampleState createState() => _SignaturePadExampleState(); } +class _SignaturePadExampleState extends State { + final GlobalKey _signaturePadKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Column( + children: [ + Container( + child: SfSignaturePad( + key: _signaturePadKey, + backgroundColor: Colors.grey[200], + ), + height: 200, + width: 300, + ), + ElevatedButton( + child: const Text('Clear Signature'), + onPressed: () { + _signaturePadKey.currentState!.clear(); + }, + ), + ], + ), + ); + } +} {% endhighlight %} {% endtabs %} @@ -306,13 +358,23 @@ Widget build(BuildContext context) { You can get the path collection of the signature drawn in the SignaturePad using the [`toPathList()`](https://pub.dev/documentation/syncfusion_flutter_signaturepad/latest/signaturepad/SfSignaturePadState/toPathList.html) method. Since this [`toPathList()`](https://pub.dev/documentation/syncfusion_flutter_signaturepad/latest/signaturepad/SfSignaturePadState/toPathList.html) method is defined in the state object of SignaturePad, you have to use a global key assigned to the SignaturePad instance to call this method. {% tabs %} -{% highlight Dart %} +{% highlight dart %} -GlobalKey _signatureGlobalKey = GlobalKey(); +import 'dart:ui'; +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_signaturepad/signaturepad.dart'; + +class SignaturePadExample extends StatefulWidget { + @override + _SignaturePadExampleState createState() => _SignaturePadExampleState(); +} -@override -Widget build(BuildContext context) { - return Scaffold( +class _SignaturePadExampleState extends State { + final GlobalKey _signatureGlobalKey = GlobalKey(); + + @override + Widget build(BuildContext context) { + return Scaffold( body: Column( children: [ Container( @@ -324,15 +386,15 @@ Widget build(BuildContext context) { width: 300, ), ElevatedButton( - child: Text("Path collection"), - onPressed: () { - List paths = - _signatureGlobalKey.currentState!.toPathList(); - }, + child: const Text('Path collection'), + onPressed: () { + final paths = _signatureGlobalKey.currentState!.toPathList(); + }, ), ], ), - ); + ); + } } {% endhighlight %} @@ -343,29 +405,34 @@ Widget build(BuildContext context) { The widget allows you to handle the [`onDrawStart`](https://pub.dev/documentation/syncfusion_flutter_signaturepad/latest/signaturepad/SfSignaturePad/onDrawStart.html), [`onDraw`](https://pub.dev/documentation/syncfusion_flutter_signaturepad/latest/signaturepad/SfSignaturePad/onDraw.html), and [`onDrawEnd`](https://pub.dev/documentation/syncfusion_flutter_signaturepad/latest/signaturepad/SfSignaturePad/onDrawEnd.html) callbacks for every stroke updated to the SignaturePad. The [`onDrawStart`](https://pub.dev/documentation/syncfusion_flutter_signaturepad/latest/signaturepad/SfSignaturePad/onDrawStart.html) callback will be called when the user starts signing on `SfSignaturePad`, the [`onDraw`](https://pub.dev/documentation/syncfusion_flutter_signaturepad/latest/signaturepad/SfSignaturePad/onDraw.html) callback will be called when updating a stroke on the [`SfSignaturePad`](https://pub.dev/documentation/syncfusion_flutter_signaturepad/latest/signaturepad/SfSignaturePad/SfSignaturePad.html), and the [`onDrawEnd`](https://pub.dev/documentation/syncfusion_flutter_signaturepad/latest/signaturepad/SfSignaturePad/onDrawEnd.html) callback will be called when the user completes signing on [`SfSignaturePad`](https://pub.dev/documentation/syncfusion_flutter_signaturepad/latest/signaturepad/SfSignaturePad/SfSignaturePad.html). {% tabs %} -{% highlight Dart %} +{% highlight dart %} + +import 'package:flutter/material.dart'; +import 'package:syncfusion_flutter_signaturepad/signaturepad.dart'; -@override -Widget build(BuildContext context) { - return Scaffold( - body: Container( +class SignaturePadExample extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Scaffold( + body: Container( child: SfSignaturePad( backgroundColor: Colors.grey[200], onDrawStart: () { return false; }, onDraw: (offset, time) { - Offset offsetValue = offset; - DateTime dateTime = time; + final offsetValue = offset; + final dateTime = time; }, onDrawEnd: () { - print("Signature has been completed in Signature Pad"); + print('Signature has been completed in Signature Pad'); }, ), height: 200, width: 300, ), - ); + ); + } } {% endhighlight %} diff --git a/Flutter/signaturepad/images/overview/signaturepad_overview.png b/Flutter/signaturepad/images/overview/signaturepad_overview.png new file mode 100644 index 000000000..afa6afc20 Binary files /dev/null and b/Flutter/signaturepad/images/overview/signaturepad_overview.png differ diff --git a/Flutter/signaturepad/overview.md b/Flutter/signaturepad/overview.md index 9dbe23cd4..c62d93861 100644 --- a/Flutter/signaturepad/overview.md +++ b/Flutter/signaturepad/overview.md @@ -2,19 +2,23 @@ layout: post title: About Flutter Signature Pad widget | Syncfusion description: Learn here all about introduction of Syncfusion Flutter Signature Pad (SfSignaturePad) widget, its features, and more. -platform: Flutter +platform: flutter control: SfSignaturePad documentation: ug --- # Flutter Signature Pad (SfSignaturePad) Overview -The SignaturePad is a widget for capturing smooth and realistic signatures. This widget allows you to save signatures as images and sync them across devices and documents that need signatures. You can use your finger, pen, or mouse on a tablet, touchscreen, or other input device to draw your own signature on this SignaturePad widget. +The Signature Pad widget helps you capture smooth, realistic signatures. It lets you save signatures as images and use them across devices and documents that require signatures. You can use your finger, pen, or mouse on a tablet, touchscreen, or other input device to draw your own signature. + +![Flutter Signature Pad](images/overview/signaturepad_overview.png) ## Features * **Signature stroke color customization** - The widget allows you to set the stroke color for the signatures. * **Signature stroke width customization** - The widget allows you to set the minimum and maximum stroke widths for the signatures. * **SignaturePad background color customization** - The widget allows you to set the background color for the SignaturePad. -* **Save as image** - The widget provides an option to save the drawn signature as an image. This converted image can be embedded in documents, PDFs, and anything else that supports using images to denote a signature. +* **Save as image** - The widget provides an option to save the drawn signature as an image. This converted image can be embedded in documents, PDFs, or any other medium that supports image-based signatures. * **More realistic handwritten look and feel** - The unique stroke rendering algorithm draws a signature based on the speed of the drawn gestures along with minimum and maximum stroke thicknesses, which brings a more realistic, handwritten look and feel to the signature. + +For step-by-step installation and setup instructions, see [Getting Started with Flutter Signature Pad](getting-started.md). \ No newline at end of file