| 导语 动态化是APP未来的趋势,腾讯成立了动态化框架中台,打造腾讯自研的动态化框架解决方案。ScrollView是动态化框架UI组件的核心之一,而物理学算法可能是其中最重要的部分之一了,好的物理学算法能给用户带来最优秀的体验。最初iOS就是以丝滑而自然的滚动体验,征服了许多用户的心。 而对于从0开始打造UI框架的动态化框架来说,这也是最重要的部分之一。用户评判一个应用是否流畅的第一反应,可能就是在页面上划一划试试,因此物理学算法的好坏,将直接影响到用动态化框架打造的应用的体验。 本文将主要分析物理学算法在ScrollView中的应用及实现方法。

一、前言

在ScrollView中,物理学算法可能是其中最重要的部分之一了,好的物理学算法能给用户带来最优秀的体验。最初iOS就是以丝滑而自然的滚动体验,征服了许多用户的心。

而对于从0开始打造UI框架的动态化框架来说,这也是最重要的部分之一。用户评判一个应用是否流畅的第一反应,可能就是在页面上划一划试试,因此物理学算法的好坏,将直接影响到用动态化框架打造的应用的体验。

本文将主要分析物理学算法在ScrollView中的应用及实现方法

二、物理学算法的相关物理属性

动画&滚动中涉及到的物理学算法属于力学算法。在本文涉及到的动画&滚动中,主要涉及到滑动摩擦和粘性阻尼两种场景。

这两种阻尼的力学运算一般涉及到以下属性。

Mass:

质量,是物体所具有的一种物理属性,是物质的量的量度,它是一个正的标量。质量分为惯性质量和引力质量。这里主要谈的是惯性质量。惯性质量是物体惯性的量度:对于m越大的物体,就越难改变其运动状态(速度)。

Velocity:

速度。表示物体运动的快慢和方向

Acceleration:

是速度变化量与发生这一变化所用时间的比值Δv/Δt,是描述物体速度变化快慢的物理量

Offset:

偏移量(位置)。弹性阻尼使用

Stiffness:

刚度。刚度是指材料或结构在受力时抵抗弹性变形的能力。是材料或结构弹性变形难易程度的表征。在宏观弹性范围内,刚度是零件荷载与位移成正比的比例系数,即引起单位位移所需的力。

Damping:

阻尼系数。在物理学和工程学上,阻尼的力学模型一般是一个与振动速度大小成正比,与振动速度方向相反的力,该模型称为粘性(或黏性)阻尼模型,是工程中应用最广泛的阻尼模型。

三、滚动过程的力学模拟分析

  • A:滚动,但是没有滚动到底部,速度逐步减小最终停止

  • B:滚动,最终会超过底部,回弹并最终停止

  • C:已经超过底部,直接回弹,但并不会反复弹,不像普通弹簧

1. 场景A

最容易想到的肯定是滑动摩擦,ScrollView由手指滑动带来了初始的速度,由于惯性的原因,ScrollView倾向于保持原有速度继续滚动,而施加的摩擦力使得滚动速度慢慢减少,最终停下来。

然而。从上面的运动曲线可以看出,滑动摩擦的匀减速运动,速度变化固定,在滚动快结束的时候其实是非常生硬的,体验并不是很好。

因此,此处也应该是采用粘性阻尼的运算方法,减速和速度挂钩,速度慢的时候减速幅度也会更小。

但是值得注意的是,如果滑动超过了边界,导致了回弹,这就不再是这种场景了。

因此该场景的判断条件为

LeadingExtent < Offset < TrailingExtent

LeadingExtent < FinalOffset < TrailingExtent

2. 场景B&场景C

场景B核心点是如果滚动很快并超过底部边界,最符合用户预期的应该是回弹停止到最底部,而不是像弹簧一样弹回来甚至反复弹。

场景C也一样,希望最终能回到边界,而不是弹力过强直接大幅度回弹。

这其实就是典型的粘性阻尼的场景了。数学的推导并不是本文的重点,因此略过。

最典型的弹簧震子运动方程是一个微分方程:

使得在参数不同的时候有不同的解。

当阻尼比=1时,方程的解为一对重实根,此时系统的阻尼形式称为临界阻尼。现实生活中,许多大楼内房间或卫生间的门上在装备自动关门的扭转弹簧的同时,都相应地装有阻尼铰链,使得门的阻尼接近临界阻尼,这样人们关门或门被风吹动时就不会造成太大的声响。

当阻尼比>1时,方程的解为一对互异实根,此时系统的阻尼形式称为过阻尼。当自动门上安装的阻尼铰链使门的阻尼达到过阻尼时,自动关门需要更长的时间。如记忆枕。

当阻尼比 <1时,方程的解的解为一对共轭虚根,此时系统的阻尼形式称为欠阻尼。在欠阻尼的情况下,系统将以圆频率相对平衡位置作往复振动。

如上图所示,平时大家常见弹簧就属于欠阻尼的情况,会反复弹动。而对于列表滚动来说,场景B和场景C一般选择欠阻尼的模式。使得超过边界的情况下,能回弹,但又不会反复回弹,最终回到边界区域。

四、物理学模块的设计和实现

根据滑动情况选择不同的物理算法

void SpringScrollPhysics::Start(float offset, float velocity, float leadingExtent,

float tailingExtent) {

ScrollPhysics::Start(offset, velocity, leadingExtent, tailingExtent);

if (offset < leadingExtent) {

scroll_type = ScrollPhysicsType::LeadingOverscroll;

calculator_ = SpringCalculator::Create(spring_, offset - leadingExtent, velocity);

} else if (offset > tailingExtent) {

scroll_type = ScrollPhysicsType::TailingOverscroll;

calculator_ = SpringCalculator::Create(spring_, offset - tailingExtent, velocity);

} else {

auto c = FrictionCalculator::Create(offset, velocity);

if (velocity > 0 && c->FinalOffset > tailingExtent) {

scroll_type = ScrollPhysicsType::TailingOverscroll;

calculator_ = SpringCalculator::Create(spring_, offset - tailingExtent, velocity);

} else if (velocity < 0 && c->FinalOffset < leadingExtent) {

scroll_type = ScrollPhysicsType::LeadingOverscroll;

calculator_ = SpringCalculator::Create(spring_, offset - leadingExtent, velocity);

} else {

scroll_type = ScrollPhysicsType::NoOverscroll;

calculator_ = c;

}

}

}

float SpringScrollPhysics::Offset(float time) {

if (scroll_type == ScrollPhysicsType::LeadingOverscroll) {

return calculator_->Offset(time) + leadingExtent_;

} else if (scroll_type == ScrollPhysicsType::TailingOverscroll) {

return calculator_->Offset(time) + tailingExtent_;

} else {

return calculator_->Offset(time);

}

}

float SpringScrollPhysics::Velocity(float time) {

return calculator_->Velocity(time);

}

bool SpringScrollPhysics::IsDone(float time) { return std::fabs(Velocity(time)) < MinimumVelocity; }

阻尼计算

shared_ptr<SpringCalculator> SpringCalculator::Create(SpringDescrition spring, float offset,

float velocity) {

float cmk = * - 4 * * spring.stiffness;

if (cmk == )

return dynamic_pointer_cast<SpringCalculator>(

make_shared<CriticalSpringCalculator>(spring, offset, velocity));

if (cmk > )

return dynamic_pointer_cast<SpringCalculator>(

make_shared<OverdampedSpringCalculator>(spring, offset, velocity));

return dynamic_pointer_cast<SpringCalculator>(

make_shared<UnderdampedSpringCalculator>(spring, offset, velocity));

}

SpringCalculator::SpringCalculator(SpringDescrition spring, float offset, float velocity)

: spring_(spring), PhysicsCalculator(offset, velocity) {}

CriticalSpringCalculator::CriticalSpringCalculator(SpringDescrition spring, float offset,

float velocity)

: SpringCalculator(spring, offset, velocity) {

r_ = - / ( * );

c1_ = offset;

c2_ = velocity / (r_ * offset);

}

float CriticalSpringCalculator::Offset(float time) {

return (c1_ + c2_ * time) * std::powf(number::e, r_ * time);

}

float CriticalSpringCalculator::Velocity(float time) {

float power = std::powf(number::e, r_ * time);

return r_ * (c1_ + c2_ * time) * power + c2_ * power;

}

OverdampedSpringCalculator::OverdampedSpringCalculator(SpringDescrition spring, float offset,

float velocity)

: SpringCalculator(spring, offset, velocity) {

float cmk = * - 4 * * spring.stiffness;

r1_ = (- - std::sqrtf(cmk)) / ( * );

r2_ = (- + std::sqrtf(cmk)) / ( * );

c2_ = (velocity - r1_ * offset) / (r2_ - r1_);

c1_ = offset - c2_;

}

float OverdampedSpringCalculator::Offset(float time) {

return c1_ * std::powf(number::e, r1_ * time) + c2_ * std::powf(number::e, r2_ * time);

}

float OverdampedSpringCalculator::Velocity(float time) {

return c1_ * r1_ * std::powf(number::e, r1_ * time) +

c2_ * r2_ * std::powf(number::e, r2_ * time);

}

UnderdampedSpringCalculator::UnderdampedSpringCalculator(SpringDescrition spring, float offset,

float velocity)

: SpringCalculator(spring, offset, velocity) {

w_ = std::sqrtf( * * spring.stiffness - * ) / ( * );

r_ = -( / * );

c1_ = offset;

c2_ = (velocity - r_ * offset) / w_;

}

float UnderdampedSpringCalculator::Offset(float time) {

return std::powf(number::e, r_ * time) *

(c1_ * std::cosf(w_ * time) + c2_ * std::sinf(w_ * time));

}

float UnderdampedSpringCalculator::Velocity(float time) {

float power = std::powf(number::e, r_ * time);

float cosine = std::cosf(w_ * time);

float sine = std::sinf(w_ * time);

return power * (c2_ * w_ * cosine - c1_ * w_ * sine) + r_ * power * (c2_ * sine + c1_ * cosine);

}

抢红包算法 c++_从0开始打造UI框架:动态化框架Scrollview物理学算法解析_搜狐汽车...相关推荐

  1. vue + element ui 的后台管理系统框架_从零开始搭建 VUE + Element UI后台管理系统框架...

    点击右上方红色按钮关注"web秀",让你真正秀起来 前言 后台管理系统前端框架,现在很流行的形式都是,上方和左侧都是导航菜单,中间是具体的内容.比如阿里云.七牛云.头条号.百家号等 ...

  2. iframe 监听内部接口是否加载完成_低成本0基础打造自己的app之uni-app请求接口以及生命周期函数...

    引言 此教程为教你怎么用WordPress开发一个属于你自己的app(小程序) 前面我们讲解了怎么用WP开发一个首页幻灯片接口(低成本0基础开发app之开发首页幻灯片接口),本来这一节中我们应该讲解如 ...

  3. 一个connection对象可以创建一个或一个以上的statement对象_从 0 开始手写一个 Mybatis 框架,三步搞定...

    来自:开源中国,作者:我叫刘半仙 链接:https://my.oschina.net/liughDevelop/blog/1631006 MyBatis框架的核心功能其实不难,无非就是动态代理和jdb ...

  4. dcf是ea211发动机吗_【图】新一代神机? 大众EA211发动机全解析_汽车之家

    [汽车之家 发动机解析]  EA211 1.4T发动机会成为大众新一代神机吗?说实话,现已搭载一汽-大众高尔夫和上海大众斯柯达明锐车型的大众EA211 1.4T发动机在技术突破程度并不及当年的大众EA ...

  5. prim算法求最小生成树_最小生成树的两种方法(Kruskal算法和Prim算法)

    关于图的几个概念定义: 连通图:在无向图中,若任意两个顶点vivi与vjvj都有路径相通,则称该无向图为连通图. 强连通图:在有向图中,若任意两个顶点vivi与vjvj都有路径相通,则称该有向图为强连 ...

  6. nubia ui 5.0 android,国内首家基于5.0开发 nubia UI 2.8体验

    MWC2015展会上,努比亚在中兴展台展出了自己旗下众多旗舰产品,还在展会上亮相了新机nubia Z9 Max.而在接下来德媒曝出的首测视频中,我们不仅看到了nubia Z9 Max各个外观设计细节, ...

  7. java python算法_用Python,Java和C ++示例解释的排序算法

    java python算法 什么是排序算法? (What is a Sorting Algorithm?) Sorting algorithms are a set of instructions t ...

  8. Dubbo-go v3.0 正式发布 ——打造国内一流开源 Go 服务框架

    简介:Dubbo-go 是常新的,每年都在不断进化.介绍 Dubbo-go 3.0 工作之前,先回顾其过往 6 年的发展历程,以明晰未来的方向. 作者 | 李志信 来源 | 阿里技术公众号 作者介绍: ...

  9. 双目立体视觉建立深度图_从单幅图像到双目立体视觉的3D目标检测算法

    原创声明:本文为 SIGAI 原创文章,仅供个人学习使用,未经允许,不能用于商业目的. 其它机器学习.深度学习算法的全面系统讲解可以阅读<机器学习-原理.算法与应用>,清华大学出版社,雷明 ...

最新文章

  1. ED2k Resource
  2. android 背景切换动画效果代码,在Android应用中以模糊效果设置背景图片
  3. 转:一个小公司老板的日常管理
  4. Apache Licene 2.0 协议说明
  5. Spark 部署及示例代码讲解
  6. windows下openresty环境配置
  7. OSPF的基本配置介绍
  8. Atitit.为什么小公司也要做高大上开源项目
  9. 高可用分布式非关系型数据库-Cassandra
  10. Centos 7镜像官网下载
  11. 光储直流微电网能量管理。 系统主要由光伏发电模块、mppt控制模块、混合储能系统模块、直流负载模块、改进前的soc限值管理控制模块
  12. 变分自编码(VAE)及代码解读
  13. 淘宝订单自动确认收货的N种实现,秒杀面试官
  14. 关于连接同一wifi,手机可以上网,电脑无法上网问题
  15. 中国电信上海电信光猫路由器设置和外接路由器
  16. webRTC H265浏览器播放器+metaRTC推流实现webRTC H265解决方案
  17. 机器学习之PQ量化算法
  18. CLK_OF_DECLARE 解析
  19. adb命令获取sys_adb shell dumpsys 命令
  20. 我的前端之路 (css篇)

热门文章

  1. UIButton高光状态(highlighted)时阴影效果
  2. [BZOJ3197][Sdoi2013]assassin(树形DP+树同构+二分图最优匹配)
  3. JS 删除数组中某个元素的几种方式
  4. 小程序/JS数组删除元素
  5. u3d中烘焙不亮怎么调整_从“提示”框:快速调整Windows大小,更改默认下载位置,DIY咖啡烘焙...
  6. 如何在js中使用ajax请求数据,在 JS 中如何使用 Ajax 来进行请求
  7. 未雨绸缪 笔记本通过手机上网技巧解读
  8. 相机标定问题-Matlab Py-Opencv
  9. 【Linux】职教云作业
  10. (翻译)NLog配置文件