自从使用了Flutter以来,闲鱼在享受着跨端带来的提效的同时,流畅度一直是困扰了我们许久的问题,也是被外界吐槽得比较多的地方。所以我们在过去半年,重新牵起了流畅度优化这件事情,目标只有一个,那就是拉平Flutter和Native的滑动体验 。
我们把这个目标拆分为了两个:
本文主要跟大家介绍一下我们在优化滑动曲线手感方面的一些经验。和优化渲染单纯的想办法提升指标不同,滑动曲线感觉是否舒服因人而异,那么我们该如何去评判一个滑动曲线是否优秀呢?说实话我们一开始也没有很好的答案。既然这样,那我们的目标首先是需要把Flutter和Native的滑动曲线进行对齐,先找回习惯的感觉再考虑下一步的优化。
我们先使用platform_tests对比一下Flutter的滑动和Native的差异
(视频的左侧列表是Native,右侧列表是Flutter)
Android
iOS
从视频的表现中,我们可以看出来iOS的脱手滑动略有差异但还是基本符合预期的,Android的脱手滑动就比较糟糕了看起来明显阻尼比Native大很多。
找滑动曲线代码的过程就不在这边过多赘述了,如果在创建滑动容器(ListView/GridView/...)时没有传入特定的physics,则Flutter会根据平台使用相应的ScrollPhysics(Android对应ClampingScrollPhysics,iOS对应BouncingScrollPhysics)。在发生Fling的时候会调用ScrollPhysics.createBallisticSimulation()
构建一个Simulation,这个Simulation(ClampingScrollSimulation/BouncingScrollSimulation)就是最终控制脱手滑动动画参数的类。
在ClampingScrollSimulation构造函数中,会根据传入的初速度,并结合一些小学二年级就学过的运动学公式计算出最终的距离以及滑动的总时间(因为没找到确定性的资料,只能根据参数推测,这边先不展开讨论)
计算出总时长和总距离后,就可以根据当前时长的比例(动画运行的时间/总时长),带入公式计算出当前应该位移的距离,最后再加上初始位置即可得到最终Viewport的偏移量。
这个公式是对Android的滑动曲线进行拟合产生的,拟合过程可以看注释,但是这个拟合并不完美。我们对这个d/t函数进行求导(即速度和时间的关系)可以发现,它的导数在0-1的区间内并不是单调递减的,这意味着在滑动接近结束的时候会有一个速度增加的情况,体感上在Clamping曲线滑动动画的末尾感觉上会有一个轻微的吸附感也说明了这一点。所以我们需要把Clamping的实现改一下,把Android的Scroller中计算滑动距离的代码弄过来。
但是我们在上面的例子中,并没有发现这个吸附的感觉,这是不是说明了这条曲线根本就没能完整地跑完呢?我们可以进一步加一些Log看一下。我们在double x(double time)
方法中把时间和position打出来,发现了一个问题,time一直在清零,position也一直在变。这说明了这个动画一直在被重新启动,我们简单改一下代码,强行让动画不要重启,使用同样的ADB指令进行滑动,通过Log对比可以发现这确实会导致滑动速度更快地衰减。
那么我们就把问题拆分成了两个:
我们在ClampingScrollSimulation
的构造函数中断点,可以发现当Fling过程中如果Item高度发生改变,则会触发RenderViewport.performLayout()
,从而触发ScrollPositionWithSingleContext.goBallistic()
,这个方法会以当前的状态为起点重新启动fling动画,这显然是不合理的,特别是当前滑动和边界无关的时候没必要因为布局改变而重启动画,这会导致一次Fling动画无法完整做完,移动的轨迹自然也就无法贴合预期中设计好的d/t曲线。
这个问题比较明确,所以解决问题的思路也很明确,就是在Fling的过程中不要重启动画了,而是去更新一些相关的变量,使得动画能够合理的继续完成。一开始我是希望更新Simulation中和边界有关的的相关参数,但是因为这个方案有个始终绕不过去的类型检查(https://github.com/flutter/flutter/pull/96512)Flutter团队的同学认为不能通过。所以诞生了下面的新方案(https://github.com/flutter/flutter/pull/100133)
首先解决更新时机的问题,当RenderViewport.performLayout()
被调用的时候,会回调ScrollActivity.applyNewDimensions
,在惯性滑动的过程中的ScrollActivity是BallisticScrollActivity
之前提到的ScrollPositionWithSingleContext.goBallistic()
也就是在这个方法中被调用,所以我们在这边做一下修改,让其不再调用goBallistic()
,而是调用updateBallisticAnimation()
生成一个新的Simulation,并将其更新到AnimationController中。
在updateBallisticAnimation()
中,我们还是使用createBallisticSimulation()
来创建Simulation。这里重要的一点是,因为我们动画时间没有清零,所以我们创建Simulation的时候一定要用初始的ScrollMetrics和Velocity来创建。因为布局变化有可能会带来相应的边界变化,所以这里只将相应的ScrollExtent(也就是边界值)更新为最新的值即可。
做完上述的操作后,我们看到了熟悉的吸附的效果,但这并不是我们想要的。为了彻底对齐与Native的体验,拟合曲线肯定是满足不了我们的,下一步我们需要将Clamping的公式彻底换成Android的Scroller.java中的实现。这时候有的小朋友可能要问了:“都要换掉它了,那我们刚才费这劲去修复它干嘛呢?”
翻译Scroller.java的代码到dart这个工作并不难,并且这部分工作其实有一位Google的同学已经做了(https://github.com/flutter/flutter/pull/77497),但是这个PR在合入后不久就被Revert了,被Revert的原因是在某些场景下会导致滑动停不下来。是的,就是因为上面提到的动画重启的问题,导致了这个滑动无法停止。所以我会在动画重启的PR被合入后,Reland这个Android曲线的PR。现在我们先来看看最后的效果,不能说是十分相似只能说是一摸一样了。
我们把曲线修改完成后开开心心地在搜索场景上线了,但是没过多久就传来噩耗,产品和交互同学一致觉得我们的滑动比以前快了很多,会影响到用户体验。
但是让我把曲线调回到那滑不动的样子,我是拒绝的。难道就没有一个方法能让用户在用的时候想仔细看的时候慢想滑走的时候快吗?算了,我们先想想看怎么让他慢下来吧。
Android和iOS两条曲线,这么多的参数,到底该把哪个调低在能在不影响滑动曲线的整体形态的同时降低体感速度呢?在很久以前Flutter其实是给iOS做过一个减速的,在BouncingScrollPhysics
创建BouncingScrollSimulation
时,给初速度乘了0.91。我们最初使用的曲线也是这个减速版本的,所以切换到正常的曲线后才会显得比较快。这个0.91在一次PR中被删除了(https://github.com/flutter/flutter/pull/59623)原因是导致了iOS曲线阻尼过大,但是实际上背后的原因,其实是上面提到的动画重启问题,因为动画重启导致速度多次乘了0.91,才使得滑动速度加速衰减。那么现在问题解决了,我们是不是也可以尝试通过这种方式对曲线进行减速。iOS的滑动公式比较简单,我们就通过iOS来分析,Android也是同样的道理。
先把初速度衰减后的曲线画出来看看。可以发现其实整体曲线的形态是没有发生变化的,只是滑动的距离减少了,这样就显得比较慢了。所以给初速度增加衰减值这个方案,是比较符合我们的预期的。
减速的问题解决了,接下来该思考一下想快的时候该怎么快起来。那么用户怎么样的一个行为才表示他现在想快点滑呢?我认为滑动速度其实一定程度上反映了用户的意愿,当用户滑动速度快的时候,天然就表示了他希望能快点滑走。顺着这个思路,如果我们给初速度的衰减值再增加一个衰减值(套起来了)让他在速度慢的时候衰减值大,速度快的时候衰减值小,就可以解决这个问题了。
这时候,灵光一现,突然想到了一个小学二年级就学过的抛物线y=ax^2+bx+c
,中间低两边高恰好满足我的诉求,当用户滑动得很慢或很快的时候不增加衰减,当用户在中速滑动的时候给出最大衰减。为了方便在线上做实验以及数据分析,我们尽量把参数缩减到一个,我选择了对称的图形(强迫症),所以必过两个点(0,1)和(1,1),并且顶点的x坐标也确定为了0.5,剩下一个顶点y坐标,初中学的顶点式就不多说了吧,直接上代码。
最终滑动的效果符合我们的预期,上线进行了分桶实验,我们得出了一个最佳实践的衰减顶点值在0.7左右,效果大概如视频所示。调整曲线的按钮是临时增加的,切换不同曲线并且使用同一个adb命令进行滑动,可以看出来使用新的曲线在快速滑动的情况下会比之前的曲线多滑动一到两屏。
本文给大家详细介绍了闲鱼优化滑动曲线手感的方案,虽然过程中遇到了不少问题,我们还算圆满地完成了任务,将Flutter的滑动手感对齐到了原生,并且根据业务场景进行了曲线速度优化。如果大家需要对曲线进行优化可以提前合入以下两个PR,上文提到的减速方案也可以根据业务情况酌情使用。
后续我们会在此基础上继续进行优化,包括但不限于以下几点:
当然了最后一点更偏向于性能优化,下一篇文章也会给大家介绍一下这段时间所做的流畅度相关的性能优化,敬请期待(一定不咕)。
本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/aqXdYYEArhEj6ikqg2oX9g
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。