I’m working at a Android TV adpated app and here is my layout,
a list item with a delete btn as trailing
to run it on tv, i need to make sure that we can switch focus to everything, but in this layout, i cant switch focus from whole item to that trailing btn by using any Arrow key.
at the begining, i figured out a way, here is my code
class ListItem extends HookWidget {
final (int, PlayableItem) e;
const ListItem(
this.e, {
super.key,
});
@override
Widget build(BuildContext context) {
// whole item focusNode
final itemFocusNode = useFocusNode();
// trailing focusNode
final trailingFocusNode = useFocusNode();
// item focus state
final itemFocused = useState(false);
//change color by item focusState
final foregroundColor = useState(Colors.black);
final bgColor = useState(Colors.transparent);
itemFocusNode.addListener(() {
itemFocused.value = itemFocusNode.hasFocus;
if (itemFocusNode.hasFocus) {
foregroundColor.value = Colors.white;
bgColor.value = Theme.of(context).primaryColor;
} else {
foregroundColor.value = Colors.black;
bgColor.value = Colors.transparent;
}
});
return Stack(
alignment: Alignment.center,
children: [
InkWell(
// for Tap and Enter interaction
focusNode: itemFocusNode,
onTap: () {
/// to support touch screen Tap and keyboard Enter key
/// seems only inkwell can do this
},
focusColor: bgColor.value, // when whole item is focused, bg is blue, otherwise transparent
child: Focus(
// to switch focus manually
onKeyEvent: (node, event) {
switch (event.logicalKey) {
case LogicalKeyboardKey.arrowRight:
// switch focus here
itemFocusNode.unfocus();
trailingFocusNode.requestFocus();
break;
default:
break;
}
return KeyEventResult.ignored;
},
child: Container()), // ignored child
),
Align(
alignment: Alignment.centerRight,
child: Padding(
padding: const EdgeInsets.only(right: 8.0),
child: PBInkWell(
/// my own inkwell to implement outline border as focused bg.
focusNode: trailingFocusNode, // trailing focusNode
focusBorderType: FocusBorderType.rect,
onTap: () => ListController.find().removeFile(e.$1),
builder: (context, isFocused, child) => SvgPicture.asset(
"assets/images/delete.svg",
width: 20,
colorFilter: itemFocused.value
? const ColorFilter.mode(Colors.white, BlendMode.srcIn)
: isFocused
? ColorFilter.mode(Theme.of(context).primaryColor, BlendMode.srcIn)
: null,
),
),
),
)
],
);
}
}
with this code, i can switch focus from whole item to it’s trailing, and by flutter default behavior, i dont need to handle the reverse version, from trailing to its parent, it can be easily switched by ‘Arrow Left’ key without any extra code.
Everything seems okay buuuuuuuuuuuuuuuuut, as you can see, this is a list and btw i’m using ReorderableListView to support reordering on touch screen, my problem is
After jumping down to an item, it works well, but after jumping up, it doesnt work.
a gif showing that issue
in this gif, i’m using only Arrow key on keyboard to control, and while jumping up to focus on the first item, i actually hit Arrow Right key so many times and it just not working. But jumping down to the second item, it works well
here is my listview code, it’s inside a drawer
class PlayerDrawer extends HookWidget {
const PlayerDrawer({super.key});
@override
Widget build(BuildContext context) {
final isReorderMode = useState(fasle);
return Container(
color: Colors.white.withAlpha((255 * 0.9).round()),
width: 300,
child: Column(
children: [
ListTile(
style: ListTileStyle.list,
leading: Text("Play List", style: Theme.of(context).textTheme.titleLarge),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (!isReorderMode.value)
PBInkWell(
onTap: ListController.find().removeAll,
builder: (context, isFocused, child) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0),
child: Text("Clear All",
style: TextStyle(
color: isFocused ? Theme.of(context).primaryColor : Colors.black,
)),
),
),
Obx(() {
final isUsingKeyboard = ListController.find().isUseKeyboard.value;
return isUsingKeyboard
? const SizedBox()
: PBInkWell(
onTap: ListController.find().switchMode,
builder: (context, isFocused, child) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0),
child: Text(isReorderMode.value ? "Done" : "Sort",
style: TextStyle(
color: isFocused ? Theme.of(context).primaryColor : Colors.black,
)),
),
);
}),
],
),
),
Expanded(
child: Obx(() {
final list = ListController.find().data;
return ReorderableListView(
onReorder: ListController.find().reorderFileList,
children: buildList(context, list),
);
}),
),
],
),
);
}
List<Widget> buildList(BuildContext context, List<PlayableItem> list) {
return list.indexed
.map(
(e) => ListItem(
e,
key: ValueKey("${e.$1}-${e.$2.uri}"),
),
)
.toList();
}
}
let me know if you need to see more code.
btw, this is output of flutter doctor -v
[✓] Flutter (Channel stable, 3.19.6, on macOS 14.3.1 23D60 darwin-arm64, locale zh-Hans-JP)
• Flutter version 3.19.6 on channel stable at /Users/inbottest2/flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 54e66469a9 (4 个月前), 2024-04-17 13:08:03 -0700
• Engine revision c4cd48e186
• Dart version 3.3.4
• DevTools version 2.31.1
[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
• Android SDK at /Users/inbottest2/Library/Android/sdk
• Platform android-34, build-tools 34.0.0
• ANDROID_HOME = /Users/inbottest2/Library/Android/sdk
• Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build 17.0.10+0-17.0.10b1087.21-11609105)
• All Android licenses accepted.
[✓] Xcode - develop for iOS and macOS (Xcode 15.4)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 15F31d
• CocoaPods version 1.15.2
[✓] Chrome - develop for the web
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
[✓] Android Studio (version 2024.1)
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 17.0.10+0-17.0.10b1087.21-11609105)
[✓] VS Code (version 1.91.1)
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.94.0
[✓] Connected device (4 available)
• AGS3 AL09HN (mobile) • 192.168.22.112:5555 • android-arm64 • Android 10 (API 29)
• Connected (mobile) • 00008110-00142D6E2E78801E • ios • iOS 17.6 21G80
• macOS (desktop) • macos • darwin-arm64 • macOS 14.3.1 23D60 darwin-arm64
• Chrome (web) • chrome • web-javascript • Google Chrome 127.0.6533.74
[✓] Network resources
• All expected network resources are available.
• No issues found!