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

Flutter复用同数据源拆分SliverMasonryGrid后滚动异常求解

问题分析与解决方案

能否实现需求?

完全可以实现这种拆分展示的需求,你遇到的滚动跳转问题是因为两个SliverMasonryGrid的列表项复用Key冲突导致的。默认情况下,Flutter的列表项会用局部索引作为复用标识,第二个Grid的项从局部索引0开始,和第一个Grid的前几项索引重复,滚动框架会错误地复用组件,引发跳转异常。

解决方法

核心是给每个列表项设置全局唯一的Key,避免复用冲突。不要依赖局部索引生成Key,而是用数据源中每个条目的唯一标识(比如数据模型的ID字段)来生成Key。

示例代码

假设你的数据源是一个包含唯一ID的模型列表:

class ItemModel {
  final String id;
  final String content;
  // 其他字段...

  ItemModel({required this.id, required this.content});
}

// 数据源
List<ItemModel> items = [
  ItemModel(id: 'item_1', content: '第一项'),
  ItemModel(id: 'item_2', content: '第二项'),
  ItemModel(id: 'item_3', content: '第三项'),
  // ...更多数据
];

然后在构建两个SliverMasonryGrid时,给每个item设置唯一Key:

CustomScrollView(
  slivers: [
    // 第一个Grid:前2条数据
    SliverMasonryGrid.count(
      crossAxisCount: 2,
      itemCount: 2,
      itemBuilder: (context, index) {
        final item = items[index];
        // 用数据的唯一ID生成Key
        return KeyedSubtree(
          key: ValueKey(item.id),
          child: YourItemWidget(item: item),
        );
      },
    ),
    // 中间的SliverToBoxAdapter
    SliverToBoxAdapter(
      child: Container(
        height: 100,
        color: Colors.grey[200],
        child: const Center(child: Text('中间分隔区域')),
      ),
    ),
    // 第二个Grid:剩余数据
    SliverMasonryGrid.count(
      crossAxisCount: 2,
      itemCount: items.length - 2,
      itemBuilder: (context, index) {
        // 取数据源的全局索引:2 + index
        final item = items[2 + index];
        // 同样用数据的唯一ID生成Key
        return KeyedSubtree(
          key: ValueKey(item.id),
          child: YourItemWidget(item: item),
        );
      },
    ),
  ],
)

关键注意点

  • 不要用局部索引(比如第二个Grid里的index)作为Key,必须用全局唯一的标识,确保两个Grid的所有项Key不重复。
  • 如果你的数据没有现成的唯一ID,也可以用全局索引生成Key,比如第二个Grid里用ValueKey('item_${2 + index}'),但推荐用数据本身的唯一标识更可靠。

内容的提问来源于stack exchange,提问作者Karol Wiśniewski

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 23:43:31