Reputation: 349
In my use case, I have multiple layouts in a particular page. for ex, in a page, i have layout(lets say layout-1) where i get the input data from user using list of textfield and then in the same page, i have another layout (lets say layout-2) in the bottom where table widget is being used to list row by row for the data that we received from user. similarly i have other layouts in the same page. I am trying to provide the keyboard shortcuts for these by using control + D, control + R etc. so the problem that i am facing is, if i focused on the texfield in layout-1 and then i press keyboard keys control + D this is focusing the expected widget correctly. but if i click outside of the texfield (anywhere in the screen on the particular page), then it loose the focus. now if i click the control + D, the shortcuts & action widget not listening the keyboard events.
In order to show this problem i just created simple code here and in this code if i click outside of the text field and if i try to use control + D, its not working.
for example, in the below code i have two textfields and i am focusing in these text fields based on shortcuts (this is just an example to explain the problem). control + R is to focus in textfield1 and control + D is to focus on textfield2. its working fine. but if i click somewhere outside of the text field and then if i try shortcuts, its not listening the keyboard events. it loose the focus.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class KeyboardShortcutTesting extends StatelessWidget {
KeyboardShortcutTesting({Key? key}) : super(key: key);
final FocusNode textfield1FocusNode = FocusNode();
final FocusNode textfield2FocusNode = FocusNode();
@override
Widget build(BuildContext context) {
return Shortcuts(
shortcuts: {
LogicalKeySet(LogicalKeyboardKey.controlLeft, LogicalKeyboardKey.keyR):
Testfield1ShorcutIntent(),
LogicalKeySet(LogicalKeyboardKey.controlLeft, LogicalKeyboardKey.keyD):
Testfield2ShorcutIntent(),
},
child: Actions(
actions: {
Testfield1ShorcutIntent:
CallbackAction<Testfield1ShorcutIntent>(onInvoke: (intent) {
print('clicked cnrl + D');
return textfield1FocusNode.requestFocus();
}),
Testfield2ShorcutIntent:
CallbackAction<Testfield2ShorcutIntent>(onInvoke: (intent) {
print('clicked cnrl + R');
return textfield2FocusNode.requestFocus();
}),
},
child: Focus(
autofocus: true,
child: Scaffold(
appBar: AppBar(title: const Text('Keyboard shortcut testing')),
body: Center(
child: Card(
color: Colors.amber[50],
child: Padding(
padding: const EdgeInsets.all(16.0),
child: SizedBox(
width: 300,
height: 200,
child: Column(
children: [
TextField(
focusNode: textfield1FocusNode,
decoration: const InputDecoration(
border: OutlineInputBorder(),
),
),
const SizedBox(height: 10),
TextField(
focusNode: textfield2FocusNode,
decoration: const InputDecoration(
border: OutlineInputBorder(),
),
),
],
),
),
),
),
)),
),
),
);
}
}
class Testfield1ShorcutIntent extends Intent {}
class Testfield2ShorcutIntent extends Intent {}
This code i am trying for flutter web. i am also attaching an image to show the problem. here if i focus either on textfield1 or texfield2 and then if i press control + D or control + R then the focus is being switched between the textfields as per the logic but i click outside of the textfield (anywhere in the yellow color card or outside of yellow color card) and then if i press then shortcuts are not working as its not even listening the keys.
Note: I also tried using FocusScope widget instead of Focus widget but FocusScope widget is not allowing to focus outside. for ex. if i use FocusScope widget and if i click outside of the textfield, its not allowing because the focus is not coming out from the textfield. it continuously focusing on the same textfield widget.
Appreciate the response!.
Upvotes: 7
Views: 1870
Reputation: 53
This is what worked for me
Wrap your scaffold with Focus scope (autofocus =true), and over that put your actions and shortcuts widget. now every time you will click on outside a focusable widget like a text field, button, etc, focus scope will take over the focus. This ensures the focus is always on your app.
@override
Widget build(BuildContext context) {
return Shortcuts(
shortcuts: ...,
child: Actions(
actions: ...,
child: FocusScope(
autofocus: true,
child: Scaffold(
...
I would recommend you to look at this thread: https://github.com/flutter/flutter/issues/111470#issuecomment-1302838704
Upvotes: 2
Reputation: 1073
Stateful Widget
for creating FocusNode
RequestFocusIntent(focusNode1)
Try out the following code,
class TextFieldShortcut extends StatefulWidget {
const TextFieldShortcut({super.key});
@override
State<TextFieldShortcut> createState() => _TextFieldShortcutState();
}
class _TextFieldShortcutState extends State<TextFieldShortcut> {
late final FocusNode focusNode1, focusNode2;
@override
void initState() {
super.initState();
focusNode1 = FocusNode();
focusNode2 = FocusNode();
}
@override
void dispose() {
focusNode1.dispose();
focusNode2.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Shortcuts(
shortcuts: {
LogicalKeySet(LogicalKeyboardKey.controlLeft, LogicalKeyboardKey.keyM):
RequestFocusIntent(focusNode1),
LogicalKeySet(LogicalKeyboardKey.controlLeft, LogicalKeyboardKey.keyQ):
RequestFocusIntent(focusNode2),
},
child: MaterialApp(
home: Scaffold(
body: Center(
child: Column(
children: [
TextField(
autofocus: true,
focusNode: focusNode1,
),
TextField(
focusNode: focusNode2,
),
],
),
),
),
),
);
}
}
Upvotes: 1