-
Notifications
You must be signed in to change notification settings - Fork 782
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Flutter on TabKey Focus not Moving Properly #2153
Comments
Hi @abdulrehmananwar , Based on the details provided, in the buildEditWidget, you have returned null for the Quantity2 column. The buildEditWidget is used to obtain the TextField widget when a cell is moved into edit mode. Therefore, while the cell was intended to be moved into edit mode, you have restricted the addition of the TextField widget by returning null. As a result, the cells in the Quantity2 column did not enter edit mode, even though focus switched to it. We believe that the cells in the Quantity2 column not entering edit mode is the issue you encountered. To better assist you with your query, could you clarify why you are restricting the addition of the TextField widget for the cells in the Quantity2 column when focus switches?. Additionally, please provide a video recording demonstrating the issue for better clarity. Please provide relevant details that may help us better understand your request. Regards, |
I am currently facing three major issues with focus management when handling the CanCellSubmit event, particularly when opening a dialog to filter search results based on user input. TextField Not Focusable: When the dialog opens, the TextField within it is not receiving focus. Even when clicked, it does not gain focus, which prevents the user from entering input. Dialog Reopening Upon Dismissal: If the dialog is dismissed without selecting any value, it unexpectedly reopens immediately. On the second dismissal, it closes properly. The dialog should only reopen if the user presses the Tab key or clicks elsewhere, not automatically upon dismissal. Focus Management in Price Column: I have a price column where user input is not required, so I do not return a TextField in the widget builder. However, this causes issues with focus traversal when using the Tab key, as the focus does not move as expected. i have shared you sample Code and video please respond on it Thanks. https://github.com/user-attachments/assets/0f5c454f-480d-4a2c-a059-c5451f4b018f |
If there are any misunderstandings regarding your requirements, or if your needs differ, please provide specific and clear details about why you are using showDialog in canSubmitCell. What is the core reason for including the dialog? This additional information will help us thoroughly address your request and provide an appropriate solution.
Regards, Abinesh P |
Point Number 3 is still pending. You suggested invoking showDialog in the buildEditWidget method for the specific cell based on the columnName, instead of directly loading the TextField widget. However, the TextField widget is necessary due to the following requirements: Unfocus Behavior: When the TextField loses focus, we need to validate the input: chrome_hyRwyuPra9.mp4 |
Issue Number 2 still not resolved. on buildEditWidget simply return null for all cells. and press tab key it not moving. properly. |
Hi @abdulrehmananwar , TextField Not Focusable: We have modified the sample according to your requirements. Instead of placing the DialogBox in the canSubmitCell method, we have now added it in the handleKeyEvent method. Additionally, we called DataGridController.endEdit to remove the focus from the TextField and allow focus to be set on the TextField within the dialog box. We have included a sample for your reference. Please review it for further details.
Press tab key it not moving Properly: We have checked on our end, and the Tab key is working properly in the DataGrid. Tab key behavior moves the focus from the current cell to the next active cell. In your case, for the price column, you have a buildEditWidget that simply returns null for all cells, so the cell does not move into edit mode. When you press Tab, the focus switches to the price cell, but the cell doesn't enter edit mode. We currently do not have direct support for copying and pasting cell content in the DataGrid. You have achieved this behavior through a custom implementation in the sample, but this approach may cause various issues in several use cases. At present, the DataGrid does not support copying and pasting cell content. However, we have already considered your request as a feature for future releases. During the planning phase of each release cycle, we review all open feature requests and prioritize them based on factors such as product vision, technological feasibility, and customer demand. We appreciate your patience and understanding as we work towards implementing this feature. You can follow up with the feedback link provided for further updates. Feedback link: 37701 Regards, |
1-You can remove Copypaste Feature from this code its not required. sboapp_FFcPdbPOsF.mp4 |
Based on the requirements, we have modified the sample to meet your needs. To open the dialog box when the TextField loses focus, we added the dialog box in the onFocusChange callback of the Focus widget. Additionally, we have addressed other focus management issues. Please refer to the sample for more details, and we have attached a video reference as well.
Video reference : Video.reference.mp4Regards, |
There are still several issues persisting: 1-When I press the Tab key without any input in the search text field, it doesn’t move to the next cell as expected. sboapp_WH3vuRstGP.mp4 |
We have addressed some of the issues and use cases in the sample. We have ensured that the specific use cases you mentioned are included, and we’ve provided a sample and video for your reference. If you encounter any other issues, please review the entire sample and provide all related use cases. This will help us verify all expected behaviors and ensure that any remaining issues are resolved.
Video : video.mp4Regards, |
1-Tab Key Navigation: Pressing Tab in the Price column causes a slight lag, making the transition feel unsmooth. Additionally, Shift+Tab does not function properly in the Price column. |
Issue 1 was resolved by defining the CustomSelectionManager in initState and passing it to the build widget, rather than defining it directly within the build widget. butt i dont want to create into initState cause i am rebuilding Gridview. so i cannot define it on initState . |
Hi @abdulrehmananwar , As per your requirements, we have modified the sample. Now, the dialog box will open when the entered value does not match any items in the list. In showSelectionDialog, we added logic to check for value matches. In the provided sample, we are currently using a local list to achieve this behavior. To assist you further, could you please provide more details about your requirements, specifically regarding fetching the list of records from an API and applying filtering? Regarding the Shift+Tab issue: all cells except for the ItemName column handle Shift key navigation and the Tab key properly. For the ItemName column, when the dialog box opens, it waits for a value to be chosen. However, this wait causes the framework to recognize the Shift key as inactive, preventing the DataGrid from detecting the Shift key press and thus disrupting navigation for this specific column. Unfortunately, this is a limitation on the DataGrid side that we cannot directly handle. If you encounter any additional issues, please review the entire sample and provide all use cases. We will test each use case to confirm that expected behaviors function properly without impacting existing features, and we’ll address any remaining issues to ensure they are fully resolved.
Video: Video.sample.mp4Regards, |
Issue 1: Initially, the CustomSelectionManager was moved to initState and passed to the build widget instead of being defined directly within the build widget. However, I would prefer not to define it in initState because I am rebuilding the GridView, so placing it in initState does not meet the requirements. Issue 2: As mentioned, the list view data comes from the API on each unfocus event. Currently, you have hardcoded this list as List searchRecord = ["1", "2", "3"];, which is fine for now. Also, please call await Future.delayed(Duration(seconds: 10)); before returning the list. This setup works as expected when pressing the Tab key, but if a user enters input and then clicks on another cell, it doesn't trigger as expected." |
Hi @abdulrehmananwar , Issue 1: We are unable to replicate the reported issue on our end. To assist you better, could you kindly provide more details regarding your requirements? Additionally, please share a video recording demonstrating the issue for better clarity. Issue 2: We are unable to achieve the desired behavior on our end. When switching the focus of the cell via a mouse click and waiting for the list, the onTap event of the cell, wrapped in a GestureDetector, gets triggered by the framework at the source level. The framework's onTap event doesn't account for the delay we have introduced, which causes the issue and prevents the required behavior from being achieved. Regards, |
Bug description
i have write a logic on buildEditWidget event after that focus travel on tab key not working properly . my code is as below.
if (column.columnName == 'Quantity2') {
return null;
}
Steps to reproduce
@OverRide
Widget? buildEditWidget(DataGridRow dataGridRow,
RowColumnIndex rowColumnIndex, GridColumn column, CellSubmit submitCell) {
// Check if the column is 'Quantity2' and return null if so
if (column.columnName == 'Quantity2') {
return null;
}
}
Code sample
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
import 'package:flutter/services.dart';
import 'package:collection/collection.dart';
class CustomSelectionManager extends RowSelectionManager {
CustomSelectionManager({
required this.isDialogOpen,
required this.dataGridController,
required this.dataGridSource,
required this.context,
required this.lastColumnIndex,
});
final bool isDialogOpen;
final DataGridController dataGridController;
final DataGridSource dataGridSource;
final int lastColumnIndex;
final BuildContext context;
@OverRide
Future handleKeyEvent(KeyEvent keyEvent) async {
if (keyEvent.logicalKey == LogicalKeyboardKey.tab ||
keyEvent.logicalKey == LogicalKeyboardKey.enter) {
if (!isDialogOpen) {
await super.handleKeyEvent(keyEvent).then(
(value) =>
WidgetsBinding.instance.addPostFrameCallback((_) async {
await dataGridController
.beginEdit(dataGridController.currentCell);
}),
);
}
}
}
}
class GridEntryDataSource extends DataGridSource {
GridEntryDataSource(this.dataGridController, this.fieldNames) {
_initializeDataList();
updateDataGridRows();
}
DataGridController dataGridController;
final List fieldNames;
List dataGridRows = [];
List<Map<String, String>> dataList = [];
// Change _isPasting to ValueNotifier
final ValueNotifier _isPasting = ValueNotifier(false);
dynamic newCellValue;
void _initializeDataList() {
dataList.add({for (var v in fieldNames) v: ''});
}
@OverRide
List get rows => dataGridRows;
void updateDataGridRows() {
dataGridRows =
dataList.map((data) => _createDataRow(data)).toList();
notifyListeners();
}
DataGridRow _createDataRow(Map<String, String> data) {
return DataGridRow(
cells: fieldNames
.map((field) =>
DataGridCell(columnName: field, value: data[field]))
.toList(),
);
}
Future handlePasteAndNavigate(
int startRowIndex, int startColumnIndex) async {
if (_isPasting.value) return;
_isPasting.value = true;
final clipboardData = await Clipboard.getData('text/plain');
}
void resetGrid() {
dataList.clear();
_initializeDataList();
updateDataGridRows();
}
Future _onCellSubmitted(
DataGridRow row, String columnName, String value) async {
final rowIndex = dataGridController.currentCell.rowIndex;
}
@OverRide
Future onCellSubmit(DataGridRow dataGridRow,
RowColumnIndex rowColumnIndex, GridColumn column) async {
// Get the current row index from the data grid controller.
final currentRowIndex = dataGridController.currentCell.rowIndex;
}
@OverRide
Future canSubmitCell(DataGridRow dataGridRow,
RowColumnIndex rowColumnIndex, GridColumn column) async {
return Future.value(true);
}
@OverRide
DataGridRowAdapter buildRow(DataGridRow row) {
return DataGridRowAdapter(
cells: row.getCells().map((cell) {
return Container(
alignment: Alignment.center,
child: Text(cell.value?.toString() ?? ''),
);
}).toList(),
);
}
@OverRide
Widget? buildEditWidget(DataGridRow dataGridRow,
RowColumnIndex rowColumnIndex, GridColumn column, CellSubmit submitCell) {
// Check if the column is 'Quantity2' and return null if so
if (column.columnName == 'Quantity2') {
return null;
}
}
}
class DataGridExample extends StatefulWidget {
const DataGridExample({super.key});
@OverRide
// ignore: library_private_types_in_public_api
_DataGridExampleState createState() => _DataGridExampleState();
}
class _DataGridExampleState extends State {
List fieldNames = ['ItemName', 'Quantity', 'Quantity2', 'Price', 'Amount'];
late DataGridController dataGridController;
late GridEntryDataSource dataSource;
String selectedOption = 'AgeFields';
@OverRide
void initState() {
super.initState();
dataGridController = DataGridController();
dataSource = GridEntryDataSource(dataGridController, fieldNames);
}
void changeColumns(String option) {
setState(() {
selectedOption = option;
fieldNames.clear();
dataGridController = DataGridController();
dataSource = GridEntryDataSource(dataGridController, fieldNames);
});
}
@OverRide
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Editable DataGrid Example'),
actions: [
ValueListenableBuilder(
valueListenable: dataSource._isPasting,
builder: (context, isPasting, child) {
return IgnorePointer(
ignoring: isPasting,
child: IconButton(
icon: const Icon(Icons.paste),
onPressed: () async {
final focusedCell = dataSource.rows.first;
int rowIndex = dataSource.rows.indexOf(focusedCell);
await dataSource.handlePasteAndNavigate(rowIndex, 0);
},
),
);
},
),
ValueListenableBuilder(
valueListenable: dataSource.isPasting,
builder: (context, isPasting, child) {
return IgnorePointer(
ignoring: isPasting,
child: IconButton(
icon: const Icon(Icons.refresh),
onPressed: () {
dataGridController.endEdit();
WidgetsBinding.instance.addPostFrameCallback(() {
dataSource.resetGrid();
});
},
),
);
},
),
],
),
body: Column(
children: [
Expanded(
child: SfDataGrid(
allowColumnsResizing: true,
selectionMode: SelectionMode.single,
navigationMode: GridNavigationMode.cell,
editingGestureType: EditingGestureType.tap,
allowEditing: true,
source: dataSource,
controller: dataGridController,
selectionManager: CustomSelectionManager(
isDialogOpen: false,
dataGridController: dataGridController,
dataGridSource: dataSource,
context: context,
lastColumnIndex: fieldNames.length - 1,
),
columns: fieldNames.map((fieldName) {
return GridColumn(
columnName: fieldName,
label: Container(
alignment: Alignment.center,
child: Text(fieldName,
style: const TextStyle(fontWeight: FontWeight.bold)),
),
);
}).toList(),
),
),
],
),
);
}
}
void main() {
runApp(const MaterialApp(
home: DataGridExample(),
debugShowCheckedModeBanner: false,
));
}
Screenshots or Video
Screenshots / Video demonstration
[Upload media here]
Stack Traces
Stack Traces
On which target platforms have you observed this bug?
Windows
Flutter Doctor output
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 3.24.4, on Microsoft Windows [Version 10.0.19045.5073], locale en-US)
[√] Windows Version (Installed version of Windows is version 10 or higher)
[√] Android toolchain - develop for Android devices (Android SDK version 35.0.0)
[√] Chrome - develop for the web
[√] Visual Studio - develop Windows apps (Visual Studio Professional 2022 17.10.4)
[√] Android Studio (version 2024.2)
[√] Connected device (3 available)
[√] Network resources
The text was updated successfully, but these errors were encountered: