百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

浅谈移动设备交互体验之惯性滚动 惯性运动的定义

bigegpt 2024-10-12 06:27 3 浏览

很久以前,手机上的交互依赖键盘和触控笔。我们要查看一个很长很长的列表,必须使用非常难用的触控笔或键盘的上下左右键。后来黑莓发明了滚动球,缓解了大拇指按出茧的问题。

2007年,苹果推出iPhone。iPhone只有一个玻璃屏,没有触控笔,直接用手指操作,支持多手指。Multi-Touch这项技术在推出时被誉为和Mouse(Mac),Click wheel(iPod)一样革命性的发明。当然最近的3D Touch(Apple watch)也是革命性的。在推出iPhone之前,苹果已经做了多年的铺垫。2005年收购的小公司finger works就是专门做手势识别的团队,用macbook的人几乎是脱离鼠标的,因为其触控板非常好用,所用技术来自这家公司。

当时有很多程序猿和产品经理讨论这个技术如何实现。疯狂的Web开发者要在浏览器上实现基于鼠标中键的滚动效果:当很快地滚动中键并停止时,页面由于惯性,会继续往下滚动一段距离才停止。有一个专业名词用来描述,叫Momentum Scrolling。还有人用Web写了示例,用来模拟手指和屏幕交互过程中的数学逻辑,iScroll 和 Scrollability 都是不错的作品。头条的Web图集也有使用Javascript(以下简称JS)实现的惯性滚动代码。下面我们用最简单的Scrollability来讲解,如何实现惯性滚动。

一. 实现滚动

HTML代码:
JS代码:



页面中有四个元素,顶部的黑条,底部的黑条,黑条中的窗口A,以及窗口内一堆英文名列表B(可以想象成办公室的卷帘)。坐标系从窗口A左上角开始,横轴X(右边为正向),纵轴Y(下边为正向)。注意,这里Y轴的方向和数学课本里相反。手指在窗口A上移动,往下移动一段距离,得到的 distanceY > 0。代码由HTML,CSS和JS构成,HTML定义了两个黑条,窗口A和卷帘B。CSS定义了他们的颜色,位置等属性。Javascript则是重点要讲的,它用来控制手指和屏幕的交互。JS中定义了几个功能和变量,其中kBounceLimit这样以k开头的,是数学公式中的固定不变的参数。startX,startY,touchX,touchY用来记录手指位置,touchAnimator是负责操作卷帘B滚动的对象。

这几行代码表示,当用户手指触碰到屏幕时,会执行onTouchStart,去做一些事情。手指在屏幕上移来移去时,会执行onTouchMove。手指离开屏幕的瞬间,硬件会通知程序手指离开,此时执行onTouchEnd。touchstart和touchend都是瞬间事件,从手指按下,移动,抬起的一套过程中只会被通知一次,touchmove是连续触发的,移动1厘米,会收到几十个通知,告诉程序当前手指坐标x,y,时间点。

让卷帘随着手指移动的办法是,在touchstart时,记录手指位置y1;touchmove时根据得到y2,算出当前移动的距离distance=y2-y1,将卷帘在y轴上移动distance距离; touchmove不断触发,不断执行前面两步,把上一次的touchmove当作起始点,紧接着触发的touchmove当作后来的点,计算distance移动卷帘。

iPhone在处理滚动的过程中,当页面已经到最顶部时,再往下拉会有弹簧效果:手指拉了一个屏幕的距离,内容只移动了半屏。用这样的代码实现其效果:

velocity的含义是:手指在屏幕移动一段距离,触发n个touchmove事件,相邻两个事件的y坐标之差就是velocity(速度)。

打个比方,老李跑步,他的步长就是 velocity。当老李还没跑,想逃出森林公园南门时会有人把他往回拉。Velocity是1米,往回拉的弹性会给velocity打折,身体移动距离可能是0.8米,具体的折扣为:

(1.0 - (position - max) / bounceLimit)*kBounceLimit

position:当前卷帘移动到的位置,(逃出南门的距离)

parentOffsetHeight : 598 窗口A的高度

nodeOffsetHeight : 4602 卷帘B的长度

max:0

min:-4004 (parentOffsetHeight-nodeOffsetHeight,卷帘被挡住的长度,从下往上拉卷帘,最多移动的距离就是min值)

absMin = min

absMax = max

bounceLimit :窗口高度 parentOffsetHeight*kBounceLimit

kBounceLimit:0.75

转换后,速度velocity衰减的系数为 0.75 - position/ 598,当position越大,velocity打折越多,越难往下拖动。

二. 惯性和回弹

接着,我们用代码实现自由滚动和下拉时的回弹

在touchend时,加入takeoff()方法





takeoff方法中,根据手指离开屏幕时的velocity计算后面滚动动画的代码:




savekeyframe方法会保存计算出来的每一帧动画,包含位置和时间点。

  1. 自由滚动时的状态:




  2. 在顶部回弹时的状态:






    position = easeOutExpo(decelStep, decelOrigin, decelDelta, kBounceTime);
    continues = ++decelStep <= kBounceTime && Math.floor(Math.abs(position)) > max;

    迭代计算position的公式为缓动曲线easeOut,接受的四个参数为:
    decelStep :初始值为0,每次减速,自增1
    decelOrigin :decelStep为0时 position值
    decelDelta :decelStep为0时 max-position
    kBounceTime :240
    对比linear,ease-in,ease-out和ease-in-out四个曲线,ease-out方程x=easeOut(t)在一开始有平缓的加速,在时间t到50%时,位置x已经快到达70%,
    在后续50%的时间内减速直到停止。符合我们平时看到的iOS滚动逻辑。






    function easeOutExpo(t, b, c, d) { return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b }
    continues的计算

    自由滚动时:continues = Math.floor(Math.abs(velocity)*10) > 0; // Math.abs(velocity) < 0.1

    顶部回弹时:continues = ++decelStep <= kBounceTime && Math.floor(Math.abs(position)) > max; // decelStep<=240加位置约束

    底部回弹时:continues = ++decelStep <= kBounceTime && Math.ceil(position) < min; //同上

  3. 底部上拉的状态,同上。

  4. saveKeyframe(!continues);
    time += kAnimationStep;

    作用是根据diff判断是否保存这个关键帧,最后得到位置和时间的运动轨迹




  5. 根据keyframes得到运动轨迹,再使用实现滚动的代码,让页面运动起来。这里就不展开说明了


    (gif图略卡,实际效果流畅很多)


三. 浏览器实现

苹果和谷歌在意识到这个需求后,为web开发者提供了原生的支持。

之前需要用iscroll等框架的需求,Chrome浏览器只需 overflow:scroll 一行代码即可。iOS设备需再加一行代码 -webkit-overflow-scrolling: touch;

原生实现的好处是

  1. 计算位置的过程要进行大量小数运算,这一点JS非常慢。

  2. 惯性滚动是苹果专利,原理涉及数学物理知识很多,远比web开发者模仿出来的要复杂,而且不开源。

  3. 如果滚动的内容非常长(手机通讯录,微信朋友圈等),要做延迟渲染,生成瓦片,贴图,销毁或者回收,内存管理,这些工作必须由系统支持,而不是业务支持。

  4. iOS支持Scroll Snapping with CSS Snap Points(点击访问),在滚动结束时对齐到内部元素,只需要两行css代码。

随着手机硬件的发展,浏览器和操作系统在图形渲染,网络API,数据存储等方面的差距越来越小。而且浏览器面向业务,对底层架构的抽象更好,一行css,一个javascript对象可以替代几千行java代码(or 几百行swift代码?)。很多只在操作系统中提供的功能,例如消息推送,也已经在浏览器实现。

Web的开放性让很多公司都对其添砖加瓦。你很难想象微软会往Android仓库中贡献代码,或者谷歌给IE浏览器解决bug,但他们确实都在为HTML5标准做贡献。另一个例子是Adobe,他们希望将Photoshop中的滤镜,图层混合模式等功能提供给web开发者,于是提议做了css filter,css blender。

http://sarasoueidan.com/demos/css-blender/



还有很多简单好玩的东西,以后会在博客中慢慢写。如有描述错误和不当,请批评指正。

作者:王伟

相关推荐

Redis集群对比:主从复制、哨兵模式、Cluster一文看懂所有优缺点

在分布式系统中,Redis作为高性能的内存数据库,其集群方案的选择直接影响到系统的稳定性、可用性和扩展性。本文将全面对比Redis的三种主流集群方案:主从复制、哨兵模式和Cluster模式,帮助开发者...

redis的主从复制,读写分离,主从切换

当数据量变得庞大的时候,读写分离还是很有必要的。同时避免一个redis服务宕机,导致应用宕机的情况,我们启用sentinel(哨兵)服务,实现主从切换的功能。redis提供了一个master,多个sl...

# Redis 入门到精通(九)-- 主从复制(3)

#Redis入门到精通(九)--主从复制(3)##一、redis主从复制-常见问题(1)###1、伴随着redis系统的运行,master的数据量会越来越大,一旦master重启...

redis - 主从复制(Redis主从复制时序图)

1引言在上一篇文章中,我们了解了Redis两种不同的持久化方式,Redis服务器通过持久化,把Redis内存中持久化到硬盘当中,当Redis宕机时,我们重启Redis服务器时,可以由RDB文件或AO...

# Redis 入门到精通(九)-- 主从复制(2)

#Redis入门到精通(九)--主从复制(2)##一、redis主从复制--数据同步阶段注意事项###1、数据同步阶段master说明1)如果master数据量巨大,数据同步阶段应...

Redis主从复制(redis主从复制主节点挂了)

介绍Redis有两种不同的持久化方式,Redis服务器通过持久化,把Redis内存中持久化到硬盘当中,当Redis宕机时,我们重启Redis服务器时,可以由RDB文件或AOF文件恢复内存中的数据。不过...

深入解析 Redis 集群的主从复制实现方式

在互联网大厂的后端开发领域,Redis作为一款高性能的内存数据库,被广泛应用于缓存、消息队列等场景。而Redis集群中的主从复制机制,更是保障数据安全、实现读写分离以及提升系统性能的关键所在。今...

Redis主从架构详解(redis主从架构高可用如何实现)

Redis主从架构搭建Redis主节点配置创建主节点目录(/opt/redis-master),复制redis.conf到该目录下,redis.conf配置项修改#后台启动daemonizeyes...

抖音“四大包塘战神”:承包了全网的快乐

在抖音钓鱼垂类领域,"包塘战神"军团正掀起一场黑色幽默风暴。空军华、大表坑、李赔光、透心良四位创作者,以承包鱼塘为舞台,用连续翻车的钓鱼直播构筑起流量奇观。当钓鱼佬在抖音集体转型喜剧人...

ORACLE 11G RAC 安装-通过VM配置共享磁盘

简介:在自己的电脑上通过VM软件搭建Oracle11GRAC,通过修改VM的参数文件来实现磁盘共享!目标:搭建RAC环境实现:使用VMwareWorkstation8.0.0+ORACLE...

Linux操作系统安全配置(linux系统安全配置包括)

一、服务相关命令systemctlenable服务名#开机自启动systemctldisable服务名#禁用开机自启动systemctlstop服务名#停止服务systemctls...

关于Linux性能调优中网络I/O的一些笔记

写在前面和小伙伴分享一些Linux网络优化的笔记,内容很浅,可以用作入门博文内容结合《Linux性能优化》读书笔记整理涉及内容包括常用的优化工具(mii-tool,ethtool,ifconfig,i...

从 Sonatype Nexus Repository Manager 迁移到 Artifactory

1.Nexus1.1下载下载链接:https://help.sonatype.com/repomanager3/product-information/download/download-archiv...

Ubuntu20安装zabbix5.0企业监控系统亲测教程

前言示例主机:zabbix10.0.100.10,将安装在UbuntuServer上教程说明:因使用官方教程无法安装成功,所以本教程与官方教程有所不同安装前提:已安装UbuntuServer2...

Linux内核设计与实现—进程管理(linux内核程序设计)

进程进程就是处于执行期的程序(目标码存放在某种存储介质上)。进并不仅仅局限于一段可执行程序代码(Unix称其为代码段,textsection)。通常进程还要包含其他资源,像打开的文件,挂起的信号,...