Flutter 如何在网格上的 TextFields 之间切换焦点(填字游戏)
Flutter how to switch focus between TextFields on a grid (a crossword)
我正在尝试创建填字游戏。我使用 GridView.count 制作填字游戏网格。我从一个列表中得到了填字游戏的模板,黑色方块用#标记并且只是黑色方块,你不能什么都不做,因为它们应该是。其余的网格单元是 TextFields,用户可以在其中输入字母来制作填字游戏。每个填字游戏都是不同的,所以我必须以编程方式创建网格。我的问题是我需要弄清楚用户想要写的单词是水平的还是垂直的,并在用户书写时让焦点从第一个单元格切换到下一个单元格(白色方块)。如何告诉它走哪条路(水平或垂直)?我还发现了 FocusTraversalGroup 和 FocusTraversalOrder,但是没有关于如何使用它们的例子。
代码如下(代码中s是包含填字游戏模板的List:
根据@DungNgo 建议编辑代码:
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
},
),
)
);
}),
)
)
);
}
}
现在光标会自动聚焦到下一个单元格,但只能水平聚焦。任何人都知道如何让它垂直“移动”?我知道 DirectionalFocusTraversalPolicyMixin 存在并且我看到了这个
focusInDirection(TraversalDirection direction) => FocusTraversalGroup.of(context!)!.inDirection(this, direction);
但我不知道如何实现它!
任何帮助将不胜感激。
谢谢
经过多次修改,我终于找到了一种方法。这是代码:
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 !!
},
),
)
);
}),
)
)
);
}
}
还有很多问题需要解决,但我的主要问题已经得到解答。
我正在尝试创建填字游戏。我使用 GridView.count 制作填字游戏网格。我从一个列表中得到了填字游戏的模板,黑色方块用#标记并且只是黑色方块,你不能什么都不做,因为它们应该是。其余的网格单元是 TextFields,用户可以在其中输入字母来制作填字游戏。每个填字游戏都是不同的,所以我必须以编程方式创建网格。我的问题是我需要弄清楚用户想要写的单词是水平的还是垂直的,并在用户书写时让焦点从第一个单元格切换到下一个单元格(白色方块)。如何告诉它走哪条路(水平或垂直)?我还发现了 FocusTraversalGroup 和 FocusTraversalOrder,但是没有关于如何使用它们的例子。
代码如下(代码中s是包含填字游戏模板的List:
根据@DungNgo 建议编辑代码:
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
},
),
)
);
}),
)
)
);
}
}
现在光标会自动聚焦到下一个单元格,但只能水平聚焦。任何人都知道如何让它垂直“移动”?我知道 DirectionalFocusTraversalPolicyMixin 存在并且我看到了这个
focusInDirection(TraversalDirection direction) => FocusTraversalGroup.of(context!)!.inDirection(this, direction);
但我不知道如何实现它! 任何帮助将不胜感激。 谢谢
经过多次修改,我终于找到了一种方法。这是代码:
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 !!
},
),
)
);
}),
)
)
);
}
}
还有很多问题需要解决,但我的主要问题已经得到解答。