浅谈移动设备交互体验之惯性滚动(移动端惯性滑动)
zhezhongyun 2025-02-04 17:07 61 浏览
很久以前,手机上的交互依赖键盘和触控笔。我们要查看一个很长很长的列表,必须使用非常难用的触控笔或键盘的上下左右键。后来黑莓发明了滚动球,缓解了大拇指按出茧的问题。
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方法会保存计算出来的每一帧动画,包含位置和时间点。
自由滚动时的状态:
在顶部回弹时的状态:
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; //同上
底部上拉的状态,同上。
saveKeyframe(!continues);
time += kAnimationStep;作用是根据diff判断是否保存这个关键帧,最后得到位置和时间的运动轨迹
根据keyframes得到运动轨迹,再使用实现滚动的代码,让页面运动起来。这里就不展开说明了
(gif图略卡,实际效果流畅很多)
三. 浏览器实现
苹果和谷歌在意识到这个需求后,为web开发者提供了原生的支持。
之前需要用iscroll等框架的需求,Chrome浏览器只需 overflow:scroll 一行代码即可。iOS设备需再加一行代码 -webkit-overflow-scrolling: touch;
原生实现的好处是
计算位置的过程要进行大量小数运算,这一点JS非常慢。
惯性滚动是苹果专利,原理涉及数学物理知识很多,远比web开发者模仿出来的要复杂,而且不开源。
如果滚动的内容非常长(手机通讯录,微信朋友圈等),要做延迟渲染,生成瓦片,贴图,销毁或者回收,内存管理,这些工作必须由系统支持,而不是业务支持。
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/
还有很多简单好玩的东西,以后会在博客中慢慢写。如有描述错误和不当,请批评指正。
作者:王伟
相关推荐
- Python入门学习记录之一:变量_python怎么用变量
-
写这个,主要是对自己学习python知识的一个总结,也是加深自己的印象。变量(英文:variable),也叫标识符。在python中,变量的命名规则有以下三点:>变量名只能包含字母、数字和下划线...
- python变量命名规则——来自小白的总结
-
python是一个动态编译类编程语言,所以程序在运行前不需要如C语言的先行编译动作,因此也只有在程序运行过程中才能发现程序的问题。基于此,python的变量就有一定的命名规范。python作为当前热门...
- Python入门学习教程:第 2 章 变量与数据类型
-
2.1什么是变量?在编程中,变量就像一个存放数据的容器,它可以存储各种信息,并且这些信息可以被读取和修改。想象一下,变量就如同我们生活中的盒子,你可以把东西放进去,也可以随时拿出来看看,甚至可以换成...
- 绘制学术论文中的“三线表”具体指导
-
在科研过程中,大家用到最多的可能就是“三线表”。“三线表”,一般主要由三条横线构成,当然在变量名栏里也可以拆分单元格,出现更多的线。更重要的是,“三线表”也是一种数据记录规范,以“三线表”形式记录的数...
- Python基础语法知识--变量和数据类型
-
学习Python中的变量和数据类型至关重要,因为它们构成了Python编程的基石。以下是帮助您了解Python中的变量和数据类型的分步指南:1.变量:变量在Python中用于存储数据值。它们充...
- 一文搞懂 Python 中的所有标点符号
-
反引号`无任何作用。传说Python3中它被移除是因为和单引号字符'太相似。波浪号~(按位取反符号)~被称为取反或补码运算符。它放在我们想要取反的对象前面。如果放在一个整数n...
- Python变量类型和运算符_python中变量的含义
-
别再被小名词坑哭了:Python新手常犯的那些隐蔽错误,我用同事的真实bug拆给你看我记得有一次和同事张姐一起追查一个看似随机崩溃的脚本,最后发现罪魁祸首竟然是她把变量命名成了list。说实话...
- 从零开始:深入剖析 Spring Boot3 中配置文件的加载顺序
-
在当今的互联网软件开发领域,SpringBoot无疑是最为热门和广泛应用的框架之一。它以其强大的功能、便捷的开发体验,极大地提升了开发效率,成为众多开发者构建Web应用程序的首选。而在Spr...
- Python中下划线 ‘_’ 的用法,你知道几种
-
Python中下划线()是一个有特殊含义和用途的符号,它可以用来表示以下几种情况:1在解释器中,下划线(_)表示上一个表达式的值,可以用来进行快速计算或测试。例如:>>>2+...
- 解锁Shell编程:变量_shell $变量
-
引言:开启Shell编程大门Shell作为用户与Linux内核之间的桥梁,为我们提供了强大的命令行交互方式。它不仅能执行简单的文件操作、进程管理,还能通过编写脚本实现复杂的自动化任务。无论是...
- 一文学会Python的变量命名规则!_python的变量命名有哪些要求
-
目录1.变量的命名原则3.内置函数尽量不要做变量4.删除变量和垃圾回收机制5.结语1.变量的命名原则①由英文字母、_(下划线)、或中文开头②变量名称只能由英文字母、数字、下画线或中文字所组成。③英文字...
- 更可靠的Rust-语法篇-区分语句/表达式,略览if/loop/while/for
-
src/main.rs://函数定义fnadd(a:i32,b:i32)->i32{a+b//末尾表达式}fnmain(){leta:i3...
- C++第五课:变量的命名规则_c++中变量的命名规则
-
变量的命名不是想怎么起就怎么起的,而是有一套固定的规则的。具体规则:1.名字要合法:变量名必须是由字母、数字或下划线组成。例如:a,a1,a_1。2.开头不能是数字。例如:可以a1,但不能起1a。3....
- Rust编程-核心篇-不安全编程_rust安全性
-
Unsafe的必要性Rust的所有权系统和类型系统为我们提供了强大的安全保障,但在某些情况下,我们需要突破这些限制来:与C代码交互实现底层系统编程优化性能关键代码实现某些编译器无法验证的安全操作Rus...
- 探秘 Python 内存管理:背后的神奇机制
-
在编程的世界里,内存管理就如同幕后的精密操控者,确保程序的高效运行。Python作为一种广泛使用的编程语言,其内存管理机制既巧妙又复杂,为开发者们提供了便利的同时,也展现了强大的底层控制能力。一、P...
- 一周热门
- 最近发表
- 标签列表
-
- HTML 教程 (33)
- HTML 简介 (35)
- HTML 实例/测验 (32)
- HTML 测验 (32)
- JavaScript 和 HTML DOM 参考手册 (32)
- HTML 拓展阅读 (30)
- HTML文本框样式 (31)
- HTML滚动条样式 (34)
- HTML5 浏览器支持 (33)
- HTML5 新元素 (33)
- HTML5 WebSocket (30)
- HTML5 代码规范 (32)
- HTML5 标签 (717)
- HTML5 标签 (已废弃) (75)
- HTML5电子书 (32)
- HTML5开发工具 (34)
- HTML5小游戏源码 (34)
- HTML5模板下载 (30)
- HTTP 状态消息 (33)
- HTTP 方法:GET 对比 POST (33)
- 键盘快捷键 (35)
- 标签 (226)
- opacity 属性 (32)
- transition 属性 (33)
- 1-1. 变量声明 (31)
