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
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.)