影响UI滚动手感的主要因素

最近在解决菜单的拖动手感问题,顺手把影响滚动手感的因素整理了一遍。

滚动是两段体验

最关键的认知是:滚动其实是两段体验。用户会把它们混在一起评价(“不跟手"“不流畅”),但两段的成因完全不同。

阶段决定手感的因素不参与的因素
手指按住时延迟、1:1跟手物理模型完全不参与
松手之后减速物理、帧节奏1:1已不重要

下面按这两个阶段来拆。

手指按住时:延迟与 1:1

位移必须严格 1:1

拖动期间,手指移动距离和UI移动距离必须是1:1的。画面必须是手指的延伸。

一旦不是1:1,大脑会立刻觉察到"这东西不完全听我的”,但用户往往说不出哪里不对,只会反馈"不跟手"。

延迟

从触摸到上屏的链路是:

触摸面板采样 -> 等屏幕同步信号 -> 上屏

这条链路加起来常常有几十毫秒。慢速拖动时延迟可能只体现为几个像素,看不出来;但快速滑动时,就是几十甚至更多像素的滞后。

延迟还受渲染链路本身影响:

  • 帧成本高,延迟更大
  • 渲染链路长且难以打断,也会明显拉高延迟

松手之后:物理惯性

松手后,惯性要像真实物体。

速度估计要准且稳

同一个甩动手势,必须每次都得到差不多的结果。速度通常取自抬手前最后二三十毫秒的瞬时速度

如果估计方式不当(比如对整段拖动做固定窗口平均、或者窗口长度不确定),就会出现"有时候滑得远,有时候几乎不滑"。这种不可预期比单纯的慢更让人心烦。

减速模型要随速度变化

主流做法是指数衰减:速度每毫秒乘一个略小于1的系数,低于阈值就停止。

它的好处是行为自然涌现,而不是预设:轻轻拨动会很快停住,猛地甩动会滑更长时间——滑行时长是速度的结果,不是一个预设常数

贯穿两段:帧节奏

帧间隔的稳定性

人眼对节奏不均匀的敏感度,远超对整体偏慢的敏感度。

稳定的30帧看起来是"流畅的慢";而60帧里偶尔插入一个30ms的长帧,会被明确感知为"卡了一下"。

动画的时间基准

掉帧无法完全避免,所以掉帧后如何处理很关键:动画应该直接跳到实际该到的位置,而不是整体变慢。

比如图标每1ms移动1px,如果掉了10ms,下次刷新应该直接到 +11px,而不是 +1px。

正确做法是:每帧读一次真实时钟,算出当前应该到的位置就直接跳过去。掉帧就掉帧,但运动的时间形状不变。

衔接两段:可打断性

内容正在惯性滑动时,手指按下必须立刻停止并接管,并且能马上再甩一次。

这一点是两个阶段之间的桥梁——如果打断不及时,用户会感觉界面在"跟自己抢方向盘"。