I'm trying to create a crossword. I make the crossword grid using GridView.count. I get the template of the crossword from a List, the black squares are marked with # and are just black squares that you cannot do nothing with, as they should be. The rest of the grid cells are TextFields where the user can write the letters to make the crossword. Every crossword is different, so I have to create the grid programmatically. My problem is that I need to figure out if the word that the user wants to write is horizontal or vertical and to get the focus to switch from the first to the next cell (white square) while the user is writing. How to tell it which way to go (horizontal or vertical)? I also found out about FocusTraversalGroup and FocusTraversalOrder but no example whatsoever on how to use them.
Here is the code (in the code s is the List containing the crossword template):
edited code after @DungNgo suggestion:
class Cells extends StatefulWidget {
@override
_CellsState createState() => _CellsState();
}
class _CellsState extends State<Cells> {
final FocusScopeNode _node = FocusScopeNode(); //new code
@override
void dispose() {
_node.dispose(); //new code
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Crossword'),
),
body: SafeArea(
child: GridView.count(
crossAxisCount: 15,
mainAxisSpacing: 2,
crossAxisSpacing: 2,
children: List.generate(s.length, (index) {
return FocusScope( //new code
node: _node, //new code
child: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: s[index] == '#' ? Colors.black : Colors.white,
border: Border.all(color: Colors.black)
),
child:
s[index] == '#' ?
Text( '#' ) :
TextField(
cursorColor: Colors.black,
textAlign: TextAlign.center,
textAlignVertical: TextAlignVertical.bottom,
decoration: InputDecoration.collapsed(hintText: ""),
style: TextStyle( decoration: TextDecoration.none),
onChanged: (text){
_node.nextFocus(); //new code
},
),
)
);
}),
)
)
);
}
}
Now the cursor focuses automatically on the next cell but only horizontally. Anyone knows how to make it "move" vertically? I know that DirectionalFocusTraversalPolicyMixin exists and I see this
focusInDirection(TraversalDirection direction) => FocusTraversalGroup.of(context!)!.inDirection(this, direction);
but I have no idea how to implement any it! Any help would be greatly appreciated. Thanks
After much tinkering I finally found a way to do it. This is the code:
class Cells extends StatefulWidget {
@override
_CellsState createState() => _CellsState();
}
class _CellsState extends State<Cells> {
isVertical = false; // added a flag
final FocusScopeNode _node = FocusScopeNode();
@override
void dispose() {
_node.dispose();
super.dispose();
}
// added a diolog to let the user choose the writing direction (horizontal or vertical)
void _showDialog() {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Direzione"),
content: Text("Scrivi in verticale?"),
actions: <Widget>[
FlatButton(
child: Text("SI"),
onPressed: () {
setState(() {
isVertical = true;
});
Navigator.of(context).pop();
},
),
FlatButton(
child: Text("NO"),
onPressed: () {
setState(() {
isVertical = false;
});
Navigator.of(context).pop();
},
),
],
);
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Crossword'),
),
body: SafeArea(
child: GridView.count(
crossAxisCount: 15,
mainAxisSpacing: 2,
crossAxisSpacing: 2,
children: List.generate(s.length, (index) {
return FocusScope(
node: _node,
child: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: s[index] == '#' ? Colors.black : Colors.white,
border: Border.all(color: Colors.black)
),
child:
s[index] == '#' ?
Text( '#' ) :
TextField(
cursorColor: Colors.black,
textAlign: TextAlign.center,
textAlignVertical: TextAlignVertical.bottom,
decoration: InputDecoration.collapsed(hintText: ""),
style: TextStyle( decoration: TextDecoration.none),
onChanged: (text){
isVertical == false ? _node.focusInDirection(TraversalDirection.right) : _node.focusInDirection(TraversalDirection.down); // this is what does it !!
},
),
)
);
}),
)
)
);
}
}
There are still many things to fix but my main question is answered.