惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

A
About on SuperTechFans
Y
Y Combinator Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Microsoft Security Blog
Microsoft Security Blog
aimingoo的专栏
aimingoo的专栏
I
InfoQ
C
Check Point Blog
IT之家
IT之家
MyScale Blog
MyScale Blog
Apple Machine Learning Research
Apple Machine Learning Research
Vercel News
Vercel News
Last Week in AI
Last Week in AI
GbyAI
GbyAI
P
Proofpoint News Feed
量子位
Stack Overflow Blog
Stack Overflow Blog
Microsoft Azure Blog
Microsoft Azure Blog
月光博客
月光博客
阮一峰的网络日志
阮一峰的网络日志
人人都是产品经理
人人都是产品经理
B
Blog
T
The Blog of Author Tim Ferriss
H
Help Net Security
云风的 BLOG
云风的 BLOG

Lanke

Google 账号地区是日本,ChatGPT 订阅为什么还是美元? 在 Flutter 项目里折腾苹果的液态玻璃效果 从“宅斗庶女”看极端女权 一期一会 关于梦 用 Vercel AI Gateway 给博客做一个 AI 摘要服务 Claude 搜索网页报错:Unable to verify if domain is safe to fetch 的解决方法 Flutter输入面板布局优化:键盘、表情面板与@联想的丝滑切换 再谈语言和思维 还有人记得 在2026年拥有自己的博客 为 Astro 博客添加 llms.txt 使用 LLM Wiki 作为 Hermes Agent 的记忆系统 使用Obsidian 作为 Hermes Agent 的记忆数据库 遇到的一起生产事故 好看的鼠标样式 拖了很久的更新,还是来了 Linux · 常用日志查询命令 面试 · Java面试二 面试 · Java面试一 如何实现验证码及校验 在电脑上共存MySQL 三道前端题 「随便来点」失语症 一些碰到的面试问题 关于博客主题的自问自答 重装电脑后恢复MySQL数据 如何畅玩旮旯game之软件篇--串流 欢迎来到实力至上主义教室 谈“诚哥”之死
流畅的下滑关闭页面
Lanke · 2026-04-26 · via Lanke

今天对音乐 App 有进行了一波优化,修了一个交互问题,感觉挺值得记录一下。

关闭播放器界面,我新增了一个手势下滑关闭,本来预期是页面跟着手指往下走。结果手指一松开,页面上会重新上滑到顶部,然后才开始下滑关闭。

问题出在哪

旧逻辑是这样的:用户往下滑,页面跟着移动一小段距离,松手的时候判断有没有达到阈值,达到了就关闭,没达到就回弹。

功能上没问题,页面确实能被关掉。但问题是用户下滑的第一帧,页面不是从手指位置开始响应的。

更具体地说,页面在某个状态下被重置了。这个重置动作在视觉上就呈现为"上来一点"。

我在代码里找了半天,发现原来手势开始时,页面先把内部状态归零,然后才去计算用户拖了多远。用户在下滑,结果页面的第一个动作是往上跳一下再开始下滑。这感觉就像你在推一扇门,结果门先往后让了一下再被你推走。

旧代码的问题

旧实现大致是这样的:

dart

GestureDetector(
  onVerticalDragStart: (details) {
    // 记录起始位置
  },
  onVerticalDragUpdate: (details) {
    // 根据增量更新偏移量
    final delta = details.primaryDelta ?? 0;
    _offset += delta;
    setState(() {});
  },
  onVerticalDragEnd: (details) {
    // 判定是否关闭
    if (_offset > threshold) {
      Navigator.pop(context);
    } else {
      _offset = 0;
      setState(() {});
    }
  },
  child: Transform.translate(
    offset: Offset(0, _offset),
    child: pageContent,
  ),
)

问题在哪?用手势的增量累加偏移量,而不是用手指的真实位移。当手势仲裁发生时,增量累加的起点和手指真实位置不同步,第一帧就会出现跳变。

怎么改的

核心思路变了:不再把下滑手势当成"触发关闭的信号",而是把它当成"用户直接控制页面位置"。

手势开始的时候,直接从手指按下的位置开始计算,不去重置任何内部状态。手势结束的时候,从当前位置继续下滑关闭,或者从当前位置回弹。不存在"重新开始"这个概念。

手势层用 GestureDetector 监听垂直拖动,更新时直接用手指的真实位移,而不是增量累加。动画层用 AnimationController.unbounded() 表达像素级位移,拖动时直接更新控制器的值,结束时从当前位置继续动画。

具体是这样:

首先定义控制器和必要的变量:

dart

late final AnimationController _dismissController = AnimationController.unbounded(
  vsync: this,
);

double _startY = 0;
double _currentOffset = 0;
static const double _dismissThreshold = 200.0;
static const Duration _dismissDuration = Duration(milliseconds: 300);

手势开始时,记录手指按下的真实位置:

dart

onVerticalDragStart: (details) {
  _startY = details.globalPosition.dy;
},

手势更新时,用当前 globalPosition.dy 减去起始位置得到真实位移,这个值直接赋给控制器:

dart

onVerticalDragUpdate: (details) {
  _currentOffset = details.globalPosition.dy - _startY;
  _dismissController.value = _currentOffset.clamp(0.0, screenHeight);
},

手势结束时,判断是继续下滑还是回弹:

dart

onVerticalDragEnd: (details) {
  final velocity = details.primaryVelocity ?? 0;
  final current = _dismissController.value;

  if (current > _dismissThreshold || velocity > 500) {
    // 从当前位置继续向下完成关闭动画,动画完再 pop
    _dismissController.animateTo(
      screenHeight,
      duration: _dismissDuration,
      curve: Curves.easeOut,
    ).then((_) => Navigator.pop(context));
  } else {
    // 从当前位置弹回原位
    _dismissController.animateBack(
      0.0,
      duration: _dismissDuration,
      curve: Curves.easeOut,
    );
  }
},

页面的位移通过 AnimatedBuilder 绑定到控制器:

dart

AnimatedBuilder(
  animation: _dismissController,
  builder: (context, child) {
    return Transform.translate(
      offset: Offset(0, _dismissController.value),
      child: child,
    );
  },
  child: pageContent,
)

改完之后

下滑的第一帧就对上了,页面从手指真实位置开始响应,不再有那个往上跳的动作。

还有一个问题也顺便解决了:之前播放器里的 PageView、歌词页这些内部内容的滚动手势,经常和关闭手势冲突。改了之后,关闭手势只绑定在顶部标题区,内部内容继续保留自己的滚动,内外不再打架。

松手之后的行为也顺了很多。之前是"达到阈值就关闭,没达到就回弹",两个动作之间有明显的切换感。现在是从当前位置继续动画,用户能看清"自己推下去的页面继续离场",而不是被某个条件突然截断。

总的来说,优化前后的核心差异很明显:优化前,用户是在“触发”一个关闭指令;优化后,用户更像是在“亲手操作”页面离场,交互感更直观、更自然。

文章标题:流畅的下滑关闭页面

文章作者:Lanke

文章链接:https://blog.blueke.top/posts/liu-chang-de-xia-hua-guan-bi-ye-mian[复制]

最后修改时间:


商业转载请联系站长获得授权,非商业转载请注明本文出处及文章链接,您可以自由地在任何媒体以任何形式复制和分发作品,也可以修改和创作,但是分发衍生作品时必须采用相同的许可协议。
本文采用CC BY-NC-SA 4.0进行许可。