Flutter how to make a selectable / focusable widget
The difference between your card with gesture detector and the ElevatedButton
is that you don't have a FocusNode
.
If you dig into the implementation details of the ElevatedButton
you will find that it uses an InkWell
with a FocusNode
final Widget result = ConstrainedBox(
constraints: effectiveConstraints,
child: Material(
// ...
child: InkWell(
// ...
focusNode: widget.focusNode,
canRequestFocus: widget.enabled,
onFocusChange: updateMaterialState(MaterialState.focused),
autofocus: widget.autofocus,
// ...
child: IconTheme.merge(
// ....
child: Padding(
padding: padding,
child: // ...
),
),
),
),
),
);
So, if you replace GestureDetector
with Inkwell
, then the keyboard navigation would work.
InkWell(
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
elevation: 10,
child: const SizedBox(
width: 200,
height: 60,
child: Center(
child: Text(
'Test 1',
),
),
),
),
onTap: () {},
)
(Tested on Android TV emulator API 30, with keyboard an d-pad.)
References
- Arrow (also D-PAD) keys don't work for focus traversal of TextFormField #49335 | github.com/flutter
- Shift+Tab and arrow (also D-PAD) keys don't work for focus traversal of TextFormField | stackoverflow.com
- How to let flutter apps support TV device? | stackoverflow.com
Nicholas Muir
Updated on January 01, 2023Comments
-
Nicholas Muir over 1 year
I am creating an android tv app. I was trying to work out for a long time why when I clicked the arrow up and down buttons on the remote it appeared to do nothing and it wasn't selecting any of the list item.
Eventually I was able to work out that if I used an elevated button or other focusable widget on the list i could use the arrow keys and it would work fine. Previously I was using a card widget wrapped in a gesture detector.
So I am wondering what the difference between a button and card with gesture detector is that stops the arrow keys from being able to select the item. I suspect it is the focus.
This is what I was using that doesn't allow the up, down keys on the remote to select it:
GestureDetector( child: Card( color: color, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(15.0), ), elevation: 10, child: SizedBox( width: (width / numberOfCards) - padding * (numberOfCards - 1), height: (height / 2) - padding * 2, child: Center(child: Text(cardTitle, style: Theme.of(context).textTheme.bodyText1?.copyWith(fontSize: 16, fontWeight: FontWeight.bold, color: Colors.white),))), ), onTap: () => onCardTap(), ),
And this is the button I replaced it with that then makes the up down keys and selection to work:
ElevatedButton( onPressed: () {}, child: Text('Test 1', style: Theme.of(context).textTheme.bodyText1?.copyWith(color: Colors.white, fontSize: 18, fontWeight: FontWeight.normal)), style: ButtonStyle( backgroundColor: MaterialStateProperty.all(Colors.grey.withOpacity(0.3)), minimumSize: MaterialStateProperty.all(Size(60, 60)), elevation: MaterialStateProperty.all(10), shape: MaterialStateProperty.all(RoundedRectangleBorder(borderRadius: new BorderRadius.circular(50)),)), ),
In case its needed this is what I am using to pick up the key presses:
Shortcuts( shortcuts: <LogicalKeySet, Intent>{ LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(), },
Thanks