diff --git a/docs/plans/2026-10-21-K87.1-pull-refresh-freeze.md b/docs/plans/2026-10-21-K87.1-pull-refresh-freeze.md new file mode 100644 index 0000000..3c1f653 --- /dev/null +++ b/docs/plans/2026-10-21-K87.1-pull-refresh-freeze.md @@ -0,0 +1,46 @@ +# K87.1 下拉刷新冻结位移实施计划 + +## 目标 + +修复刷新 pending 期间仍从松手距离回收到 56px 的视觉回弹。达到阈值后冻结当前下拉距离 D,刷新完成前 offset 不变化,完成后才用 200ms easeOut 回到 0。 + +## 根因 + +- K87 已将系统 physics 改为 Clamping,避免原生 overscroll 回弹叠加。 +- 但 `_refresh` 仍先执行 `_animateOffsetTo(_holdDistance)`,会把松手时的 D(例如 96)回收到 56。 +- 用户感知为“页面已经弹回去”,实际是组件自身在刷新开始时主动缩短 offset。 + +## 范围 + +- ReelShort `lib/core/widgets/app_pull_to_refresh.dart` +- ReelShort `test/core/app_pull_to_refresh_test.dart` +- FruitServer `docs/plans/PROGRESS.md` + +## 实现计划 + +1. 保留 `AlwaysScrollableScrollPhysics(parent: ClampingScrollPhysics())`,系统不移动 overscroll 内容。 +2. 删除 `_holdDistance` 与刷新前的 56px 过渡动画。 +3. 达到阈值松手后立即进入 refreshing,AnimationController 保持当前 D;刷新期间滚动通知和手势均忽略。 +4. `onRefresh` 完成后再从 D 执行 200ms easeOut 回 0,指示器随 offset 淡出。 +5. 未达阈值松手时新增 `_retracting` 状态,执行 200ms easeOut 回到 0,不触发 `onRefresh`。 + +## 测试计划 + +- 达阈值测试:记录松手 offset D,挂起 300ms 后仍等于 D;刷新中重复下拉不改变 D、不增加调用。 +- complete 后断言 offset 回 0、指示器消失。 +- 未达阈值测试:松手后立即开始回弹,100ms 时 offset 介于 0 与 D 之间,最终回 0 且 `onRefresh` 未调用。 +- 断言 `AppPullToRefresh.physics.parent` 为 `ClampingScrollPhysics`。 + +## 风险与处理 + +- 保持 D 时下拉越高,内容下移越明显,但这是用户松手时的真实位置,刷新完成后才回收。 +- 未达阈值回弹期间通过 `_retracting` 忽略新滚动通知,避免动画目标被手势覆盖。 +- 不逐个页面改动,所有使用共享 physics 与组件的页面自动生效。 + +## Git + +- ReelShort 从 `develop` 创建 `fix/pull-refresh-freeze`。 +- 提交:`fix(ui): 下拉刷新刷新期间冻结下拉位移`。 +- 作者:`Zhou Weidong <502333560@qq.com>`。 +- `--no-ff` 合回 `develop` 并 push,不使用 force push,不执行 `git add -A`。 +- FruitServer 追加 PROGRESS 留痕;不安装真机,完成后等待用户验收。 diff --git a/docs/plans/PROGRESS.md b/docs/plans/PROGRESS.md index c0d0a8f..8ea93cf 100644 --- a/docs/plans/PROGRESS.md +++ b/docs/plans/PROGRESS.md @@ -23616,3 +23616,26 @@ $ flutter test --no-pub ``` 解读:ReelShort 静态检查零告警,514 条测试全部通过。未安装真机,等待用户验收。 + +## 2026-10-21 ReelShort:K87.1 下拉刷新刷新期间冻结位移 + +- 修正分支:`fix/pull-refresh-freeze`,从 ReelShort develop `01bef7f` 创建。 +- 功能提交:`35860e0 fix(ui): 下拉刷新刷新期间冻结下拉位移`。 +- develop 合并提交:`e6f3497 merge: 合并 K87.1 下拉刷新冻结位移修复`,已推送 `01bef7f..e6f3497`。 +- 经核对,K87 已将 `AppPullToRefresh.physics` 改为 `AlwaysScrollableScrollPhysics(parent: ClampingScrollPhysics())`,K87.1 保留该配置,不再依赖原生 overscroll 位移。 +- 删除 `_holdDistance` 和刷新前“当前距离 → 56px”的动画。达到阈值松手后 AnimationController 冻结在松手距离 D,刷新期间忽略滚动通知并阻止手势,`onRefresh` 完成后才从 D 执行 200ms easeOut 回 0。 +- 未达阈值松手新增 `_retracting` 状态,从当前距离执行 200ms easeOut 回 0;回弹期间忽略新手势,不触发刷新。 +- 测试红灯复现:达阈值 D=96 时旧实现会变成 56,偏差 40;未达阈值松手旧实现立即从 30 变为 0。修复后 pending 300ms 仍保持 D,重复下拉不增加调用;未达阈值 100ms 时 offset 仍介于 0 与 D 之间,最终回 0。 + +门禁原始输出: + +```text +$ dart analyze lib test +Analyzing lib, test... +No issues found! + +$ flutter test --no-pub +01:35 +515: All tests passed! +``` + +解读:ReelShort 静态检查零告警,515 条测试全部通过。未安装真机,等待用户验收。