You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

开发填字游戏:如何在按下任意字母键时触发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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 20:20:58