I have a ModalBottomSheet containing a GridView of cards with FocusNode which I would like to navigate using Keyboard or RemoteControl and highlighting the selected card.
The navigation between focusnodes working fine in my code but the color of all cards is always the same even when isFocused == true
.
Here is the code I've been trying to make work:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
onGenerateRoute: (RouteSettings settings) {
switch (settings.name) {
case '/':
return MaterialWithModalsPageRoute(
builder: (_) => MyHomePage(title: 'Flutter Demo Home Page'),
settings: settings);
}
return MaterialPageRoute(
builder: (context) => Scaffold(
body: CupertinoScaffold(
body: Builder(
builder: (context) => CupertinoPageScaffold(
child: Center(
child: Container(),
),
),
),
),
),
settings: settings,
);
},
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool? isFocused = false;
late List<FocusNode> fnList;
@override
void initState() {
super.initState();
fnList= List.generate(7, (int index) => FocusNode());
_firstFocus();
}
void _firstFocus(){
for(int i=0;i<7;i++){
//print("Listener added on focus number $i");
fnList[i].addListener((){
if (fnList[i].hasFocus != isFocused) {
setState(() {
print("SET STATE isFocused from $isFocused");
isFocused = fnList[i].hasFocus;
print("To $isFocused");
});
}
});
}
}
@override
void dispose() async {
super.dispose();
for(int i=0;i<=7;i++){
fnList[i].dispose();
}
}
_changeFocus(FocusNode node){
node.requestFocus();
}
Color iconColor = Colors.blue;
@override
Widget build(BuildContext context) {
return Material(
child: Scaffold(
body: CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
transitionBetweenRoutes: false,
middle: const Text('Modal Presentation'),
trailing: GestureDetector(
child: const Icon(Icons.arrow_forward),
onTap: () => Navigator.of(context).pushNamed('ss'),
),
),
child: SizedBox.expand(
child: SafeArea(
bottom: false,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
section('STYLES'),
RawKeyboardListener(
focusNode: FocusNode(),
child: ListTile(
title: const Text('Cupertino Modal fit'),
onTap: () => showCupertinoModalBottomSheet(
expand: false,
context: context,
backgroundColor: Colors.transparent,
builder: (context) => GridView.builder(
primary: true,
physics: const BouncingScrollPhysics(),
shrinkWrap: true,
gridDelegate:
const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200,
childAspectRatio: 6/5,
crossAxisSpacing: 7,
mainAxisSpacing: 7
),
scrollDirection: Axis.vertical,
itemCount: 7,
itemBuilder: (BuildContext context, int index) =>
Focus(
focusNode: fnList[index] ,
autofocus: (index==0)?true:false,
onKey:(node, event) {
if (event.isKeyPressed(LogicalKeyboardKey.arrowRight)) {
_changeFocus(fnList[index+1]);
print(fnList);
//print(isFocused);
print("---------------------------------------------------");
} else if (event.isKeyPressed(LogicalKeyboardKey.arrowLeft)) {
_changeFocus(fnList[index-1]);
print(fnList);
//print(isFocused);
print("---------------------------------------------------");
}
else if (event.isKeyPressed(LogicalKeyboardKey.arrowUp)) {
_changeFocus(fnList[index-5]);
print(fnList);
//print(isFocused);
print("---------------------------------------------------");
}
else if (event.isKeyPressed(LogicalKeyboardKey.arrowDown)) {
_changeFocus(fnList[index+5]);
print(fnList);
//print(isFocused);
print("---------------------------------------------------");
}
else if (event.isKeyPressed(LogicalKeyboardKey.enter)) {
print(index);
print("---------------------------------------------------");
}
return KeyEventResult.handled;
},
onFocusChange: (hasFocus)
{
if(hasFocus)
{
iconColor = Colors.red;
}
else{
iconColor = Colors.blue;
}
setState((){});
},
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Container(
height: 100,
width: 100,
color: iconColor,
),
),
),
),
),),
),
const SizedBox(
height: 60,
)
],
),
),
),
),
),
);
}
Widget section(String title) {
return const Padding(
padding: EdgeInsets.fromLTRB(16, 20, 16, 8),
);
}
}