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

Flutter Web滚动GridView时出现‘Assertion failed:_pressedKeys.containsKey(event.physicalKey)’错误的求助

Flutter Web: GridView.builder滚动时出现KeyUpEvent断言错误且滚动卡顿

问题描述

我通过POST请求从API获取数据后,使用GridView.builder展示数据。在应用的Web版本中,数据能正常显示,但一旦开始滚动,调试控制台就会抛出KeyUpEvent断言错误,同时滚动变得非常卡顿,动画完全失效。

错误信息

════════ Exception caught by services library ═════════════════════════════════
在平台消息回调期间抛出了以下断言:
Assertion failed: ../…/services/hardware_keyboard.dart:441
_pressedKeys.containsKey(event.physicalKey)
"A KeyUpEvent is dispatched, but the state shows that the physical key is not pressed. If this occurs in real application, please report this bug to Flutter. If this occurs in unit tests, please ensure that simulated events follow Flutter's event model as documented in `HardwareKeyboard`.
This was the event: KeyUpEvent#6f053(physicalKey: PhysicalKeyboardKey#700e3(usbHidUsage: \"0x000700e3\", debugName: \"Meta Left\"), logicalKey: LogicalKeyboardKey#4b191(keyId: \"0x200000106\", keyLabel: \"Meta Left\", debugName: \"Meta Left\"), character: null, timeStamp: 0:01:32.201000, synthesized)"
抛出异常时的调用栈:
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 251:49 throw_
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 29:3 assertFailed
packages/flutter/src/services/hardware_keyboard.dart 441:46 <fn>
packages/flutter/src/services/hardware_keyboard.dart 451:14 [_assertEventIsRegular]
packages/flutter/src/services/hardware_keyboard.dart 543:5 handleKeyEvent
packages/flutter/src/services/hardware_keyboard.dart 821:57 handleRawKeyMessage
dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 84:54 runBody
dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 123:5 _async
packages/flutter/src/services/hardware_keyboard.dart 808:51 handleRawKeyMessage
packages/flutter/src/services/platform_channel.dart 73:49 <fn>
dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 84:54 runBody
dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 123:5 _async
packages/flutter/src/services/platform_channel.dart 72:58 <fn>
packages/flutter/src/services/binding.dart 379:35 <fn>
dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 84:54 runBody
dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 123:5 _async
packages/flutter/src/services/binding.dart 376:98 <fn>
lib/_engine/engine/platform_dispatcher.dart 1034:13 invoke2
lib/ui/src/ui/channel_buffers.dart 25:5 invoke
lib/ui/src/ui/channel_buffers.dart 65:7 push
lib/ui/src/ui/channel_buffers.dart 130:16 push
lib/_engine/engine/platform_dispatcher.dart 302:25 invokeOnPlatformMessage
lib/_engine/engine/keyboard.dart 130:39 [_handleHtmlEvent]
lib/_engine/engine/keyboard.dart 39:7 <fn>
═══════════════════════════════════════════════════════════════════════════════

相关代码

@override
Widget build(BuildContext context) {
  return Container(
    child: Scaffold(
      body: Row(
        children: [
          SideDrawer(),
          Container(
            padding: EdgeInsets.all(20),
            width: MediaQuery.of(context).size.width * 0.77,
            child: FutureBuilder<dynamic>(
              future: appList(),
              builder: (context, snapshot) {
                if (snapshot.data == null) {
                  return Center(
                    child: CircularProgressIndicator(),
                  );
                } else {
                  return GridView.builder(
                    gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                        crossAxisCount: 5,
                        childAspectRatio: 3 / 2,
                        crossAxisSpacing: 10,
                        mainAxisSpacing: 10),
                    itemCount: snapshot.data.length - 1,
                    itemBuilder: (context, index) {
                      return Card(
                        elevation: 2,
                        child: ListTile(
                          leading: Text(snapshot.data[index]["title"]),
                        ),
                      );
                    },
                  );
                }
              },
            ),
          ),
        ],
      ),
    ),
  );
}

解决方案

1. 升级Flutter到最新稳定版

这个KeyUpEvent断言错误是Flutter Web在旧版本中的已知bug,已经在后续的稳定版中修复。执行以下命令升级:

flutter upgrade

2. 优化FutureBuilder的使用方式

你当前在FutureBuilder的future参数中直接调用appList(),这会导致每次build方法执行时都重新发起API请求,不仅浪费资源,还会引发不必要的组件重建,加剧滚动卡顿。

修改方法:在initState中初始化Future,避免重复请求:

late Future<dynamic> _appListFuture;

@override
void initState() {
  super.initState();
  // 只在组件初始化时发起一次请求
  _appListFuture = appList();
}

@override
Widget build(BuildContext context) {
  return Container(
    child: Scaffold(
      body: Row(
        children: [
          SideDrawer(),
          Container(
            padding: EdgeInsets.all(20),
            width: MediaQuery.of(context).size.width * 0.77,
            child: FutureBuilder<dynamic>(
              future: _appListFuture, // 使用初始化好的Future
              builder: (context, snapshot) {
                // ... 原有代码保持不变
              },
            ),
          ),
        ],
      ),
    ),
  );
}

3. 修复GridView的布局约束问题

你的GridView嵌套在Row的Container中,没有明确的高度约束,这会导致Flutter在滚动时反复计算布局,引发卡顿。可以通过以下两种方式解决:

  • 方式一:用Expanded替代Container
    将包裹FutureBuilder的Container替换为Expanded,让它自动填充Row的剩余空间,同时给GridView提供明确的高度约束:

    Expanded(
      child: Padding(
        padding: EdgeInsets.all(20),
        child: FutureBuilder<dynamic>(
          future: _appListFuture,
          builder: (context, snapshot) {
            // ... 原有代码保持不变
          },
        ),
      ),
    )
    
  • 方式二:给Container设置明确高度
    如果需要固定宽度,可以给Container添加高度约束:

    Container(
      padding: EdgeInsets.all(20),
      width: MediaQuery.of(context).size.width * 0.77,
      height: MediaQuery.of(context).size.height, // 填充屏幕高度
      child: FutureBuilder<dynamic>(
        // ... 原有代码保持不变
      ),
    )
    

4. 可选:优化GridView的性能

如果数据量较大,可以添加addAutomaticKeepAlives: false和addRepaintBoundaries: false来减少不必要的组件重建(根据实际情况调整,若Card内容复杂可能需要保留):

GridView.builder(
  addAutomaticKeepAlives: false,
  addRepaintBoundaries: false,
  gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
    crossAxisCount: 5,
    childAspectRatio: 3 / 2,
    crossAxisSpacing: 10,
    mainAxisSpacing: 10,
  ),
  // ... 其他参数保持不变
)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 11:44:05