开发填字游戏:如何在按下任意字母键时触发Action?
实现任意字母键触发填字方块更新的方案
完全可行,不用局限于SingleActivator或CharacterActivator的单个按键限制,直接通过监听键盘事件并判断输入字符即可实现类似[a-zA-Z]的匹配效果。以下是两种实用的实现方式:
方法一:利用FocusNode的onKey回调
给每个填字方块绑定独立的FocusNode,在焦点的onKey回调中过滤字母按键,触发内容更新。这种方式能精准响应当前聚焦方块的按键操作:
class CrosswordTile extends StatefulWidget { const CrosswordTile({super.key}); @override State<CrosswordTile> createState() => _CrosswordTileState(); } class _CrosswordTileState extends State<CrosswordTile> { late FocusNode _tileFocusNode; String _tileContent = ''; @override void initState() { super.initState(); _tileFocusNode = FocusNode() ..onKey = (node, event) { // 仅处理按键按下事件,避免重复响应 if (event is RawKeyDownEvent) { final inputChar = event.character; // 用正则匹配单个字母(大小写均可) if (inputChar != null && RegExp(r'^[a-zA-Z]$').hasMatch(inputChar)) { setState(() { _tileContent = inputChar.toUpperCase(); // 统一转为大写,可按需调整 }); return KeyEventResult.handled; // 标记事件已处理,阻止向下传递 } } return KeyEventResult.ignored; // 忽略非字母按键 }; } @override void dispose() { _tileFocusNode.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Focus( focusNode: _tileFocusNode, child: GestureDetector( // 点击方块获取焦点 onTap: () => _tileFocusNode.requestFocus(), child: Container( width: 55, height: 55, decoration: BoxDecoration( border: Border.all(color: Colors.grey.shade700), color: _tileFocusNode.hasFocus ? Colors.lightBlue.shade100 : Colors.white, ), child: Center( child: Text( _tileContent, style: const TextStyle(fontSize: 28, fontWeight: FontWeight.w600), ), ), ), ), ); } }
方法二:使用RawKeyboardListener
通过RawKeyboardListener包裹方块组件,监听全局键盘事件,结合焦点状态判断是否响应当前方块的按键:
class CrosswordTile extends StatefulWidget { const CrosswordTile({super.key}); @override State<CrosswordTile> createState() => _CrosswordTileState(); } class _CrosswordTileState extends State<CrosswordTile> { String _tileContent = ''; late FocusNode _focusNode; bool _isFocused = false; @override void initState() { super.initState(); _focusNode = FocusNode(onFocusChange: (focused) { setState(() => _isFocused = focused); }); } @override void dispose() { _focusNode.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return RawKeyboardListener( focusNode: _focusNode, onKey: (event) { if (event is RawKeyDownEvent && _isFocused) { final inputChar = event.character; if (inputChar != null && RegExp(r'^[a-zA-Z]$').hasMatch(inputChar)) { setState(() { _tileContent = inputChar.toLowerCase(); // 统一转为小写,可按需调整 }); } } }, child: GestureDetector( onTap: () => _focusNode.requestFocus(), child: Container( width: 55, height: 55, decoration: BoxDecoration( border: Border.all(color: Colors.grey.shade700), color: _isFocused ? Colors.lightGreen.shade100 : Colors.white, ), child: Center( child: Text( _tileContent, style: const TextStyle(fontSize: 28, fontWeight: FontWeight.w600), ), ), ), ), ); } }
关键注意事项
- 可以通过
toUpperCase()或toLowerCase()统一输入字符的大小写,适配填字游戏的显示需求; - 必须判断
event is RawKeyDownEvent,避免按键抬起时重复触发更新; - 点击方块时调用
requestFocus()确保焦点落在当前方块,才能响应按键操作。
内容的提问来源于stack exchange,提问作者bwk
相关产品推荐
相关产品推荐

