#flutter #focus #textfield
#flutter #фокус #текстовое поле
Вопрос:
Я пытаюсь создать кроссворд. Я создаю сетку кроссвордов с помощью GridView.count. Я получаю шаблон кроссворда из списка, черные квадраты отмечены # и являются просто черными квадратами, с которыми вы ничего не можете сделать, как и должно быть. Остальные ячейки сетки — это текстовые поля, в которые пользователь может вписать буквы, чтобы составить кроссворд. Каждый кроссворд отличается, поэтому мне приходится создавать сетку программно. Моя проблема в том, что мне нужно выяснить, является ли слово, которое пользователь хочет написать, горизонтальным или вертикальным, и переключить фокус с первой на следующую ячейку (белый квадрат), пока пользователь пишет. Как указать, в какую сторону двигаться (горизонтально или вертикально)? Я также узнал о FocusTraversalGroup и FocusTraversalOrder, но никаких примеров о том, как их использовать.
Вот код (в коде s находится список, содержащий шаблон кроссворда):
отредактированный код после предложения @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);
но я понятия не имею, как это реализовать!
Любая помощь будет принята с благодарностью.
Спасибо
Комментарии:
1. Для 2-го вопроса вы можете использовать FocusScope.of(context).nextFocus() и поместить его в OnChanged() текстового поля.
2. @Dung Ngo спасибо, я пытался, но у меня получилось странное зацикливание от текстового поля к текстовому полю… Я попробую еще раз удалить узлы фокусировки в другом месте, возможно, в этом и была проблема … есть идеи, как переместить фокус по вертикали? Я думаю, по умолчанию используется горизонтально…
3. Кто-нибудь? Даже просто указатель в каком-то направлении? пробовал все, что мог придумать, и никакой радости…
Ответ №1:
После долгих размышлений я наконец нашел способ сделать это. Это код:
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 !!
},
),
)
);
}),
)
)
);
}
}
Есть еще много вещей, которые нужно исправить, но на мой главный вопрос дан ответ.