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

Flutter如何通过RawKeyboardListener获取条码扫描结果?

实现逻辑说明

安卓设备内置条码扫描模块的输出逻辑,默认是将扫描得到的条码内容模拟成快速连续的键盘输入事件,条码输入完成后会自动追加一个结束标识(绝大多数设备默认是回车符)。RawKeyboardListener 就是通过捕获这串连续按键事件,拼接得到完整条码结果。
核心判断依据:扫码触发的按键输入间隔极短(通常单字符间隔小于100ms),远快于人工手动输入速度,可以通过按键间隔过滤人工输入的干扰,遇到结束符时就得到完整条码。

实现步骤
  • 维护3个状态变量:缓存拼接中的扫码内容字符串、记录上一次按键的时间戳、全局持久化的FocusNode(不要在build方法里临时创建FocusNode,会导致焦点异常、捕获失效,页面销毁时要手动dispose)。
  • 按键回调中只处理RawKeyDownEvent事件,忽略RawKeyUpEvent避免重复捕获字符。
  • 每次触发按键事件先判断和上一次按键的时间差,如果间隔超过300ms,判定不属于同一次扫码输入,清空内容缓存。
  • 识别到回车结束符时,当前缓存的字符串就是完整条码结果,执行业务逻辑后清空缓存准备下一次扫码。
  • 非结束符的普通可打印字符,直接拼接到缓存字符串中即可,过滤掉Shift、Ctrl这类无字符输出的控制按键。
完整示例代码
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class BarcodeScanPage extends StatefulWidget {
  const BarcodeScanPage({super.key});

  @override
  State<BarcodeScanPage> createState() => _BarcodeScanPageState();
}

class _BarcodeScanPageState extends State<BarcodeScanPage> {
  // 缓存扫码过程中的内容
  String _scanBuffer = '';
  // 记录上一次按键时间
  DateTime? _lastKeyPressTime;
  // 持久化焦点节点
  late final FocusNode _scanFocusNode;
  // 存储最终扫描结果用于展示
  String _finalScanResult = '暂未扫描到条码';

  @override
  void initState() {
    super.initState();
    _scanFocusNode = FocusNode();
  }

  @override
  void dispose() {
    _scanFocusNode.dispose();
    super.dispose();
  }

  void _handleKeyEvent(RawKeyEvent event) {
    // 只处理按键按下事件,跳过抬起事件防止重复
    if (event is! RawKeyDownEvent) return;

    final currentTime = DateTime.now();
    // 按键间隔超过阈值,判定为非扫码输入,清空缓存
    if (_lastKeyPressTime != null &&
        currentTime.difference(_lastKeyPressTime!).inMilliseconds > 300) {
      _scanBuffer = '';
    }
    _lastKeyPressTime = currentTime;

    // 捕获到回车结束符,扫码完成
    if (event.logicalKey == LogicalKeyboardKey.enter) {
      if (_scanBuffer.isNotEmpty) {
        setState(() {
          _finalScanResult = _scanBuffer;
        });
        // 此处可添加扫码成功的业务逻辑,比如查询商品、跳转页面等
        _scanBuffer = '';
      }
      return;
    }

    // 拼接普通可打印字符
    final inputChar = event.character;
    if (inputChar != null && inputChar.isNotEmpty) {
      _scanBuffer += inputChar;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('条码扫描')),
      body: Center(
        child: RawKeyboardListener(
          focusNode: _scanFocusNode,
          autofocus: true,
          onKey: _handleKeyEvent,
          child: Padding(
            padding: const EdgeInsets.all(16.0),
            child: Text(
              _finalScanResult,
              style: const TextStyle(fontSize: 20),
            ),
          ),
        ),
      ),
    );
  }
}
适配注意事项
  • 部分设备可以自定义扫码结束符,如果默认回车无法触发结果回调,可以去设备系统的条码设置页查看结束符配置,修改对应按键判断逻辑即可。
  • 如果页面内存在TextField等会抢占输入焦点的组件,需要在扫码场景下保证焦点落在_scanFocusNode上,否则会无法捕获按键事件。
  • 按键间隔阈值可以根据自己设备的扫码速度调整,100ms-500ms区间都可正常使用,既不会截断同一次扫码内容,也能有效过滤人工输入干扰。

内容的提问来源于stack exchange,提问作者VolkanUstekidag

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 08:44:04