如何在Flutter Staggered Grid View中实现类Google Keep的钉选笔记置顶分组
基于staggered_grid_view实现Google Keep风格钉选笔记方案
前置适配
- 笔记数据库层已经完成
pinned布尔字段扩展,查询笔记列表时直接按pinned DESC, 更新时间 DESC排序拉取,返回结果天然是钉选笔记在前、普通笔记在后,省去客户端二次排序的性能开销 - 推荐使用
flutter_staggered_grid_view: ^0.7.0及以上版本,该版本原生支持嵌套Sliver组件构建分区分组,无需手动计算网格偏移量
核心组件搭建逻辑
不要直接用单实例
StaggeredGridView.count装载全量笔记,将整个页面视图替换为CustomScrollView结构,把分组标题、网格内容拆分为独立Sliver组件依次拼接,从根源上实现分组边界可控
- 第一步:封装可复用的笔记网格生成方法,传入对应分组的笔记列表,返回适配的
SliverMasonryGrid组件:SliverMasonryGrid( gridDelegate: const SliverSimpleGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, // 保持Google Keep同款双列交错布局 ), delegate: SliverChildBuilderDelegate( (context, index) { final currentNote = groupNoteList[index]; return NoteCard(note: currentNote); // 复用现有开发完成的笔记卡片组件 }, childCount: groupNoteList.length, ), ) - 第二步:通过
SliverMainAxisGroup把每个分组的标题、对应网格内容绑定为独立区块,按顺序排布两个分组区块:CustomScrollView( slivers: [ // 钉选笔记分组区块 SliverMainAxisGroup( slivers: [ // pinned分组标题 SliverPadding( padding: const EdgeInsets.fromLTRB(16, 24, 16, 8), sliver: SliverToBoxAdapter( child: Text( 'pinned', style: Theme.of(context).textTheme.titleSmall, ), ), ), // 钉选笔记网格,无内容时返回空占位 if (pinnedNoteList.isNotEmpty) buildNoteGrid(pinnedNoteList), ], ), // 普通笔记分组区块 SliverMainAxisGroup( slivers: [ // others分组标题,加足上下间距做区域视觉区分 SliverPadding( padding: const EdgeInsets.fromLTRB(16, 32, 16, 8), sliver: SliverToBoxAdapter( child: Text( 'others', style: Theme.of(context).textTheme.titleSmall, ), ), ), // 普通笔记网格 buildNoteGrid(otherNoteList), ], ) ], ) - 第三步:细节优化还原Google Keep效果:
- 两个分组区块之间预留足够的垂直内边距,也可以在普通笔记标题上方加一根1px高度、低透明度的分割线,强化区域区分感
- 钉选状态变更时,仅需要在本地分组数组中移动对应笔记条目(从普通组移除、插入钉选组最前,或反向操作),触发组件刷新即可,无需对全量列表做重排计算
避坑提醒
- 不要使用低版本
StaggeredGridView的全量列表模式硬塞分组标题,这种模式下标题会被识别为网格单个条目,无法跨列铺满,必然出现布局错位 - 当对应分组没有笔记时,直接隐藏对应分组的标题,和Google Keep的交互逻辑保持一致
- 分组内的笔记卡片高度差异可以完全保留原有实现,
SliverMasonryGrid会自动完成列方向的对齐,不需要手动调整每个卡片的网格高度占比
内容的提问来源于stack exchange,提问作者Babsky
相关产品推荐
相关产品推荐

