抢红包算法 c++_从0开始打造UI框架:动态化框架Scrollview物理学算法解析_搜狐汽车...
| 导语 动态化是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物理学算法解析_搜狐汽车...相关推荐
- vue + element ui 的后台管理系统框架_从零开始搭建 VUE + Element UI后台管理系统框架...
点击右上方红色按钮关注"web秀",让你真正秀起来 前言 后台管理系统前端框架,现在很流行的形式都是,上方和左侧都是导航菜单,中间是具体的内容.比如阿里云.七牛云.头条号.百家号等 ...
- iframe 监听内部接口是否加载完成_低成本0基础打造自己的app之uni-app请求接口以及生命周期函数...
引言 此教程为教你怎么用WordPress开发一个属于你自己的app(小程序) 前面我们讲解了怎么用WP开发一个首页幻灯片接口(低成本0基础开发app之开发首页幻灯片接口),本来这一节中我们应该讲解如 ...
- 一个connection对象可以创建一个或一个以上的statement对象_从 0 开始手写一个 Mybatis 框架,三步搞定...
来自:开源中国,作者:我叫刘半仙 链接:https://my.oschina.net/liughDevelop/blog/1631006 MyBatis框架的核心功能其实不难,无非就是动态代理和jdb ...
- dcf是ea211发动机吗_【图】新一代神机? 大众EA211发动机全解析_汽车之家
[汽车之家 发动机解析] EA211 1.4T发动机会成为大众新一代神机吗?说实话,现已搭载一汽-大众高尔夫和上海大众斯柯达明锐车型的大众EA211 1.4T发动机在技术突破程度并不及当年的大众EA ...
- prim算法求最小生成树_最小生成树的两种方法(Kruskal算法和Prim算法)
关于图的几个概念定义: 连通图:在无向图中,若任意两个顶点vivi与vjvj都有路径相通,则称该无向图为连通图. 强连通图:在有向图中,若任意两个顶点vivi与vjvj都有路径相通,则称该有向图为强连 ...
- nubia ui 5.0 android,国内首家基于5.0开发 nubia UI 2.8体验
MWC2015展会上,努比亚在中兴展台展出了自己旗下众多旗舰产品,还在展会上亮相了新机nubia Z9 Max.而在接下来德媒曝出的首测视频中,我们不仅看到了nubia Z9 Max各个外观设计细节, ...
- java python算法_用Python,Java和C ++示例解释的排序算法
java python算法 什么是排序算法? (What is a Sorting Algorithm?) Sorting algorithms are a set of instructions t ...
- Dubbo-go v3.0 正式发布 ——打造国内一流开源 Go 服务框架
简介:Dubbo-go 是常新的,每年都在不断进化.介绍 Dubbo-go 3.0 工作之前,先回顾其过往 6 年的发展历程,以明晰未来的方向. 作者 | 李志信 来源 | 阿里技术公众号 作者介绍: ...
- 双目立体视觉建立深度图_从单幅图像到双目立体视觉的3D目标检测算法
原创声明:本文为 SIGAI 原创文章,仅供个人学习使用,未经允许,不能用于商业目的. 其它机器学习.深度学习算法的全面系统讲解可以阅读<机器学习-原理.算法与应用>,清华大学出版社,雷明 ...
最新文章
- ED2k Resource
- android 背景切换动画效果代码,在Android应用中以模糊效果设置背景图片
- 转:一个小公司老板的日常管理
- Apache Licene 2.0 协议说明
- Spark 部署及示例代码讲解
- windows下openresty环境配置
- OSPF的基本配置介绍
- Atitit.为什么小公司也要做高大上开源项目
- 高可用分布式非关系型数据库-Cassandra
- Centos 7镜像官网下载
- 光储直流微电网能量管理。 系统主要由光伏发电模块、mppt控制模块、混合储能系统模块、直流负载模块、改进前的soc限值管理控制模块
- 变分自编码(VAE)及代码解读
- 淘宝订单自动确认收货的N种实现,秒杀面试官
- 关于连接同一wifi,手机可以上网,电脑无法上网问题
- 中国电信上海电信光猫路由器设置和外接路由器
- webRTC H265浏览器播放器+metaRTC推流实现webRTC H265解决方案
- 机器学习之PQ量化算法
- CLK_OF_DECLARE 解析
- adb命令获取sys_adb shell dumpsys 命令
- 我的前端之路 (css篇)
热门文章
- UIButton高光状态(highlighted)时阴影效果
- [BZOJ3197][Sdoi2013]assassin(树形DP+树同构+二分图最优匹配)
- JS 删除数组中某个元素的几种方式
- 小程序/JS数组删除元素
- u3d中烘焙不亮怎么调整_从“提示”框:快速调整Windows大小,更改默认下载位置,DIY咖啡烘焙...
- 如何在js中使用ajax请求数据,在 JS 中如何使用 Ajax 来进行请求
- 未雨绸缪 笔记本通过手机上网技巧解读
- 相机标定问题-Matlab Py-Opencv
- 【Linux】职教云作业
- (翻译)NLog配置文件