驯服 Flutter 无限滚动(二):用 CubitSignalMixin 把 ScrollController 变成响应式状态机
来源:dev.to — 2026-09-04
📋 概述
系列第 2 篇针对 pub.dev 上几十个第三方分页包(infinite_scroll_pagination、lazy_load_scrollview 等)收的「架构税」给出替代:把 Flutter 标准 ScrollController 本身变成响应式状态容器。Dart 的单继承墙挡住了 `class X extends ScrollController, BlocSignal`,但通过可组合的 CubitSignalMixin / BlocSignalMixin 可以绕过。作者给出两种模式:A 用一个只发「是否接近底部」布尔信号的 PagingScrollController 保持领域层 100% 纯 Dart;B 让 controller 同时是 ScrollController、Cubit 与 Bloc,做到 100% StatelessWidget 的 UI。
🔑 核心要点
- 第三方分页包的架构税:劫持 widget 树逼你用 PagedListView 之类专有包装、引入与既有 BLoC 竞争的第二个 truth source、还在 UI 生命周期里试图解并发
- Dart 单继承墙可被混入绕开:ScrollController 继承 ChangeNotifier,mixin 进 CubitSignalMixin 得到 state/stateValue/emit 与自动去重,再叠 BlocSignalMixin 就有 on 与 droppable/restartable 变换器
- 像素胜过百分比:`position.extentAfter <= 200` 固定给「距底约两个条目」的一致提前量,而 `offset >= maxScrollExtent*0.9` 在短列表提前 100px、在 5 万像素长列表提前 5000px——疯狂提前加载用户根本不会滚到的地方
- 自动去重在 emit 内比较 newState==currentState:接近底部时连发几十次滚动通知,emit(true) 重复调用零杂散更新,只在越界向下与回滚向上各触发一次
- 模式 A 让领域 BLoC 保持纯 Dart 不 import flutter,UI 用一句 `pagingController.createEffect(...)` 声明式把「接近底部」接成 `postsBloc.add(PostsFetched())`
- 模式 B(Self-Paging Mixin)把 controller 变成统一单一事实源:ScrollController+Cubit+Bloc 一体,UI 层完全不写 initState/dispose 样板、可做到 100% StatelessWidget;Pure Dart 派选 A,求速度与最少样板选 B
💡 金句
无限滚动不必是充满竞态 bug、竞争控制器与专有包装器的成人礼。
👍 0
👎 0
← 返回 dev.to 首页