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

推荐订阅源

V
Visual Studio Blog
爱范儿
爱范儿
GbyAI
GbyAI
博客园 - 叶小钗
Last Week in AI
Last Week in AI
Jina AI
Jina AI
Microsoft Security Blog
Microsoft Security Blog
云风的 BLOG
云风的 BLOG
C
Check Point Blog
H
Help Net Security
P
Proofpoint News Feed
酷 壳 – CoolShell
酷 壳 – CoolShell
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
大猫的无限游戏
大猫的无限游戏
H
Hackread – Cybersecurity News, Data Breaches, AI and More
B
Blog RSS Feed
Y
Y Combinator Blog
U
Unit 42
T
Tailwind CSS Blog
MyScale Blog
MyScale Blog
N
Netflix TechBlog - Medium
S
SegmentFault 最新的问题
J
Java Code Geeks
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知

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进行许可。