当我们设计师输出了精美的设计稿,然后附带了一个流畅的手势动画,交付给开发的时候,也期待着开发大佬搞出和自己预期一样体验流畅。但是等到实际体验的时候,却发现有一种说不出的闹心。
“这个感觉不好按…”
“划起来咋这么费劲呢?”
“怎么感觉动画怪怪的。”
当你正准备和开发一通友好探讨的时候,这个时候开发向你发起了一系列灵魂拷问:
“你这个左滑的手势,划多少才算触发?划多快才算触发?如果划了一半划回去算不算触发?如果我先点击后滑动算不算触发?松手之后的动画是多快的速度?什么速度曲线?要不要回弹效果?回弹阻尼系数是多少?”
这个时候你发现,自己提出的设计需求根本太天真了。
1. 系统组件无法直接调用了
刚才的问题真实原因是,在做很多手势识别或者一些我们看起来日常的效果,其实是蕴含了很多复杂逻辑的。
这些复杂逻辑原本被封装在操作系统内,在系统内可以随时调用。但是一旦脱离了操作系统,那手势的处理逻辑就会比较简陋,导致最终的体验不佳。
那这个时候也许你会想问,我们怎么会脱离操作系统呢?我们的手机不都是 iOS 和 Android 的吗?不都是操作系统吗?其实这里指的操作系统,是指操作系统的原生组件。这类组件只有在原生开发中才能被调用。
如今,很多 App 都使用前端语言来开发内部页面(HTML/CSS/JS)。随着 Web 混合开发,Flutter 等跨端技术栈的出现,越来越多的团队开始拥抱这样的跨平台技术栈。在节约了开发成本的同时,随之而来的就是,在日常开发过程中,离纯原生组件越来越遥远。
在这样的背景下,研发团队的体验设计师需要自己来研究用户行为,手势、组件和动效,实现原生组件类似的复杂逻辑,才能最大程度的接近甚至超越原生组件的体验。
2. 不加处理的直接调用前端接口
其实使用各个技术框架,也是有内置一些接口的。例如一些事件监听器 / 动效曲线等。这也是腾讯文档之前一直在使用的,但是会遇到一些问题。总结下来,主要有以下几个问题:
无法精确操作:用户的操作和操作反馈被自己的手指挡住,无法完成精确操作。
手势识别误触:同一热区支持了多个手势,可是用户的实操时的手势动作又没那么标准,导致用户误触其他手势。
手势触发费力:滑动费劲,需要滑动很长距离才能触发预期的动作。
动画不流畅:各个技术框架自带的动画曲线和插值器,良莠不齐,体验不统一且不够流畅。
3. 系统组件背后的复杂逻辑
对于原生组件,我们习以为常的系统控件和手势设计,里面蕴含的智慧远比我想象的更多。
举个简单的例子:iOS 系统的首页,它可以支持横竖各个方向的滑动,并且在触发一个方向的手势之后,就无法再触发其他手势了。
但是其实有个问题,手指和平时演示的不太一样。
就是手指贴合上屏幕的时候,手指与屏幕的贴合面,并不是均匀向四周扩散的,而是向下的扩散更大一些。对于触摸中心点,在触摸的过程中,就会有向下的一个偏移。
如果直接识别,这个偏移直接被识别为向下滑动,那就会无法触发左右滑动的手势。
例如在 iOS 内的手势识别,有一个专门的接口来做识别:PanGestureRecognizer,这个接口会在 10px 内先判定手指移动的方向和距离,再对具体触发的手势来做定义。例如下图,虽然刚开始手指位置有些许下移,但是最终还是可以左滑判定成功。
所以你会发现,如果在 iOS 桌面上轻微的向左右滑动(10pt 内),桌面是不会有任何响应的。就是因为在 10pt 内,系统还无法确认手势的方向。
另外,系统还自带了很多手势反馈操作,包括回弹效果,甩出效果。里面的小逻辑设计需要非常精准。并且对于滑动的手势还带了回弹效果,看起来非常爽。
4. 打造流畅体验设计
腾讯文档是基于 Web / Flutter 的应用,并且接管了很多原生系统的能力,包括排版能力、光标选区能力,拖动能力等。因此,很多基于 Native 开发能很简单解决地问题,在 Web 下就要重新打磨一套我们日常习以为常却逻辑复杂的组件。
由于腾讯文档是基于 Web 的的应用,接管了很多原生系统的能力,所以不能使用系统的 Gesture Recognizer,也不能使用系统的选区光标能力。
如果是简单的使用前端的操作监听器,那会要求用户使用极其标准的手势操作才能触发,否则就会触发失败。因此需要设计更精准且适应性的规则,来包容用户不那么标准的实操手势。需要帮助用户在粗糙的实操手势下,猜测用户原图,并精准完成的操作。
1. 常用手势的进阶定义
可能你以为手势操作并不常用,其实并不是的。一个单击,一个双击,其实本质上都是手势。
不过,很多人可能会认为,按说这些操作都有原生的监听器,不需要再去定义。但是其实如果不做一些进阶定义,就会出现操作不灵敏的问题。例如下面这个问题:
在很多安卓手机上,或者是我们自己的腾讯文档里,时常遇到一个问题:就是原本以为双击文本区域可以选中文字,可是却发现这个双击成了一个玄学事件。双击有时生效而有时不生效。理想的双击大概是这样的,是需要 2 次有效的 Tap 事件:
这个 Bug 让我们来定位一下。让我们还原一下事情的经过:
哦!原来是因为双击的其中一稍微偏移了一下,拖动到了光标,导致系统判定是一次 Tap 一次 Drag 的行为,这样就没有办法触发双击行为了。解决方法也很简单。把 10px 偏移距离内的滑动行为都判定为点击行为就可以了。从这里看,我们其实需要做的是,规范“点击”这个手势的定义。因为原来的系统自带定义,容易造成误操作,而且手指贴上屏幕的时候,都会产生轻微位移,或者一不小心滑动了页面,或者不小心拖动了光标,导致手势识别的不灵敏。
原定义:“点击并在 500ms 内在原处松手”。需重新定义为:“点击并在在 500ms 内,在 10px 以内处松手”。另外,文档移动端也定义了一系列更进阶的手势的操作,在这样对手势的进阶定义后,操作可以被更精准和智能的判断。这些定义被写在了设计规范中,包括了单击 / 双击 / 长按 / 拖拽。
2. 光标拖动&长按选中
腾讯文档的整个文本编辑区域都是使用 Canvas 实现的,由前端自主控制渲染。因此,选区光标就无法直接使用系统能力,需要设计师来设计一套选区光标,并且支持系统的各种选区光标的手势。由于腾讯文档的光标选区是非常基础的编辑组件。这个组件在一般的产品中,都是直接复用的系统组件,但是在腾讯文档中,就需要重新去考虑光标组件。
首先有个需求,光标是可以在文本中快速拖动的。
经常会遇到拖动。无论是光标拖动,还是长按选中,我们都希望能清楚的看到光标的位置,所以我们在用户拖动光标和选区的时候,被拖动的组件会放大 1.5 倍,使用户可以看到拖动效果。
这就够了吗?不够的。
如果用户想要精准的控制光标,首先要让用户完整的看到光标。用户在拖动光标的时候,手指经常会不自觉的向下移动。这是为了让自己看清光标,这个时候,我们不应该把这个移动当做是把光标向下移动一行,光标本身不应该跟随向下,应该只在同一行,并且只响应左右移动。
但是当我向下拖更多距离的时候,光标就应该一直保持在手的上方,以确保用户可以精确操作。
同样,我们定义了长按后可以拖动选择的手势。在拖动的过程中,允许用户向下偏移一定的区域,来看清选区的具体边界位置。
手机端的光标选区,一个我们日常习以为常的光标,里面竟然有那么多小细节在里面,才能让光标变得好用。
3. 滑动触发规则
当一个滑动手势被触发时,我应该如何判断这个手势已经被触发了呢?这个判断并非简单的横划竖划,而是针对不同的场景,去做特殊处理的。
案例 1:向下滑动手势
例如说,一个非常简单的手势,半屏向下滑动关闭。我们通常来说我们的日常体验,会是一个对距离的判断,当手指拖动容器超过一定的距离,然后松手,就可以触发手势。
但是仅仅判断距离是不够的。因为手势是对现实世界的映射。很多时候用户希望滑动很短的距离,把东西“甩”出去。
如果仅仅判断距离,那就很难“甩”出去。这时候就还需要判定用户手指在离屏时的速度了。最后能达成一个比较轻松就能触发手势的结果。
案例 2:左右切换相机
这是腾讯文档的文档扫描页面。上半屏是大面积的取景画面,底部是文档类型的选择。因为取景页面可以点击对焦和测光,因此轻微的滑动不应该导致整个取景页面或者底部 Tab 的滑动,应当是当整个页面检测到一个比较大的滑动动作之后,才自动移动切换。
但是如果需要离手才能触发,如果用户划动的速度比较慢,整个体验也会随之变得过于拖沓。所以这里还加了一条逻辑:当手指滑动速度的加速度急剧减小时,不用松手也可以触发手势。这样的体验感会觉得流畅很多。
在腾讯文档中,点击、滑动、悬浮、长按等手势操作贯穿用户的使用过程,动画效果是所有交互操作的视觉反馈,也许它没有那么的「高逼格」,但它却是这台精密仪器运转不可缺少的“润滑剂”,流畅愉悦的动效能够让体验更美好。
但是由于腾讯文档起初是基于 web 混合开发,后面又加入了 Flutter 框架,这就导致多个平台、框架的动效逻辑混在一起,在这个背景下,设计师们就需要从多方面重新梳理并定义动画的基础规则。
1. 自然流畅
自然流畅是腾讯文档内所有动效运行的基础原则。
由于腾讯文档是基于 Web、flutter 等多框架混合开发的应用,动画曲线又都是基于各自框架自带的贝塞尔曲线(cubic-bezier),这就经常导致一些同类型的手势操作,最后所呈现的动画效果却相差很多。并且原生的动画曲线,在实际使用上并没有达到很好的效果,只是能够比没有动画要强上一些。因此,确定一套统一、自然并且适合腾讯文档的动画曲线,是设计师优先要解决的问题。
为此我们根据动画使用的场景,定义了四种标准曲线。同时输出给开发同学,作为标准可调用的曲线。
缓动(Ease Both)
缓动曲线应用的场景最为广泛,也是腾讯文档的默认曲线。相对于传统 web 端或者 flutter 框架内的默认曲线,腾讯文档的缓动曲线开始时会比较迅速,这样能给用户及时反馈、高效运行的感受;在运动快结束的阶段,为了避免快速反馈带来急躁的负面感受,曲线会更加平缓,进而使正在运动的元素吸引用户的注意力,并让用户能够有一定的思考时间,保证动画的合理性。
缓出(Ease Out)
即减速曲线。运动元素在开始阶段时位移变化会很大,但是后面会越来越小。缓出曲线前期快速运动,不需要过多让用户留意,在结束的时候逐渐减慢速度,让用户关注到其新的状态,用户就可以提前切入到定位寻找的阶段,等动画停止后就可以立即进行操作。这种类型的曲线通常是用在元素进入界面时使用。
弹性(Spring)
弹性曲线是一种基于阻尼弹性振荡的原理实现的复杂曲线,阻尼比决定了曲线具体动画感受,根据阻尼比的不同,弹性曲线可以分为三种,分别是欠阻尼运动、临界阻尼运动及过阻尼运动。在腾讯文档中,通常只会使用到欠阻尼运动及临界阻尼运动。
弹性曲线却并不适合在所有的使用场景中,因为这种运动一般情况会需要相对多一些的时间来完成整个运动过程,让整个过程变得过于拖沓。同时过于活泼的弹性动画也会过分的吸引用户注意力,打断主进程的操作,影响效率。
运动时长
时长是元素移动所需的时间,在创建自然流畅的动画中起着重要作用。如果动画太慢,会使用户感到卡顿和厌烦;但是如果速度太快,就会给人紧张急迫的感觉。因此动画的持续时间应该给与用户充分的反应时间,同时又不用过久等待为标准。
在移动端上,我们设定动画的持续时间在 300-400ms。而在 web 端上,我们设定动画的持续时间在 200-300ms 内。具体的运动时长视具体动画而定,时长并不一成不变。
2. 积极肯定
曲线是动效的灵魂,有时候你觉得平凡的动画,或许只需要简单地拨动那条运动曲线,就可以让这个动画瞬间变得充满灵气。尽管曲线可以解决大部分动效问题,但在动画的实际落地中,还是有一些问题,是它无法解决的。这就会涉及到动画更底层的渲染及逻辑。比如说在 web 端,前端动画卡顿与否其实是和动画本身实现性能有关系的,浏览器的屏幕刷新率都可能被代码拖慢。这也是腾讯文档在初期并没有在 web 端增加太多动画的原因,过多的动画效果其实意味着需要更多的性能资源倾斜到动画上。
3. 高效愉悦
在动画上除了希望提供自然流畅的积极体验,我们也希望继续深入,“让工具褪去冷冰的外壳,走进与智能隔空对话的新世界”。让体验更有情感,让用户更愉悦。
在待办事项上,优化前每当用户点击完成一项事项时,完成动画仅仅是机械的从未完成向完成图标的替换,反馈效果非常“高效”的完成了它的任务,但是这样就足够了么?不一定,当一项事项被列为待办时,就证明这件事对于用户来说是重要的。在现实中,当重要的事情完成时,我们都是欢欣的,就像心里在放烟花,完成待办时候的动画理应如此,让用户在完成的那一刻体验到“烟花”的绽放。
但是总有一些产品,或者是通用性的考虑,或者是一些历史原因,或者是一些成本考量,走上了非原生开发的路,这样的产品在未经打磨的情况下直接一股脑搞出来,的确会显得卡顿,或者难用。这其中不仅需要工程师一点一滴的性能优化,而且也对体验设计师对细节的把控提出了更高的要求。只有对用户的行为处处关照,才能无限接近最极致的体验。
实战案例!腾讯文档全平台系统设计复盘
背景
“操作系统对我们而言已不是最重要的了,更重要的是应用和服务。” [1]- 微软 CEO Satya Nadella
去年微软发布的便携折叠屏设备 Surface Duo 首次搭载了来自 Google 的安卓系统,而微软 CEO 也在随后的采访中表示 Windows 系统已不是微软未来的重心,他们更关心开发者如何为这些设备创造应用,无论这个平台是 Windows 还是安卓。
阅读文章 >>
以下是腾讯文档 APP 和小程序二维码链接,欢迎大家扫码体验!
欢迎关注作者微信公众号:「腾讯ISUX」