哈Ha!
有一次,产品负责人要求我们考虑创建一个有效的过程,以将动画引入我们的android / ios应用程序。 当时,我们的任务是用贷款产品的个人数据预填充应用程序,服务器花了一些时间来响应,在此期间我们想要展示漂亮的加载动画。
任务很明确:设计人员希望绘制精美的图形,以便将两者的源代码都提供给
没有dopilivaniya的平台,因此它不会滞后于较旧的设备(是的,我们仍然支持android 4.1)。
我介绍动画有哪些选择:- 使用可绘制动画矢量的笔。 好在渲染效果很好
在单独的线程中(从api 25开始),缺点是创建此类动画的复杂性以及对象的少量操作。 对于简单的动画,这一切都很好,但是稍微复杂一点,然后开始。 是的,在其他平台上您将无法启动。 - Gif-它们很重,尺寸固定,这意味着它们无法正常缩放。 而且您不会对它们进行任何特殊操作。
- png序列(无评论)。
在android和gif的本机矢量动画的方向上挖了一段时间(天哪,我们仍然考虑使用此选项),我想起了很棒的Lottie库,并把它展示给了我的同事们。
在使用各种设备进行了一些测试之后,我们决定应该实施该库,特别是因为其功能令人印象深刻。 设计师特别高兴,现在他可以在Adobe After Effects中制作几乎任何动画,然后单击几下即可导出到json文件。 我们也很高兴,但首先是第一件事。
Lottie是由Airbnb发明和实施的,以响应对跨平台动画的日益增长的需求,因此它在所有平台上均能(几乎)正常工作。 开发人员自己声称他们的目标是实现最大数量的After Effects功能,并且他们成功地做到了。 现在,嵌入Lottie动画就像将图片插入ImageView一样容易。
关键3类:- LottieAnimationView是ImageView的后继者,并且是使用动画的最简单方法。 您可以在xml中描述动画,也可以在代码中支持大多数方法。
- LottieDrawable-Drawable后代,具有与上一类相同的功能,可让您将动画应用于任何视图。
- LottieComposition及其伴随的LottieCompositionFactory可让您从各种来源预加载动画,并将其应用于LottieDrawable和LottieAnimationView。
资源加载
支持从以下资源加载资源:
- 分辨率/原始
- src /资产
- 杰森弦
- 网络中指向json或zip文件的任何url(通过HttpURLConnection实现,以免添加外部依赖关系。如果您的图像带有动画,则需要使用zip)
- InputStream json或zip文件
动画缓存
很酷的事情是,所有通过res / raw或资源下载的动画都由LRU缓存保存,这使我们不会浪费用户的时间重新加载和解析动画,因为在复杂动画的情况下,可能需要一些时间。 更酷的是,如果您需要预加载动画,然后在下一个片段中立即显示动画,则可以使用代码
LottieCompositionFactory.fromRawRes(context, rawFile)
动画使用rawFile键进行缓存,在您真正需要使用它的地方,它几乎立即开始播放。
进度管理
Lottie允许您通过setProgress(...)设置当前动画状态。 如果您想为文件上传状态,滚动位置,各种手势等设置动画,这可以派上用场。 我在BottomSheets,PullToRefresh,CollapsingToolbarLayout上看到了各种实现。
这是在AppBarLayout中使用进度的方法:
appBarLayout.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset -> val percent = Math.abs(verticalOffset).toFloat()/appBarLayout.totalScrollRange animationView.progress = percent })
循环播放
Lottie支持循环setRepeatMode()或setRepeatCount()不仅循环整个动画,而且循环(0.0 ... 1.0)内的任何片段。 这由属性setMinFrame,setMaxFrame,setMinAndMaxFrame实现。 我们这样做是为了不对不同的文件上传状态实现3种动画:空闲,进度,完成。 这是解决此问题的一小段代码:
when (loadingStatus) { LoadingStatus.IDLE -> { animationView.setMaxProgress(0.1f) } LoadingStatus.PROGRESS -> { animationView.setMinAndMaxProgress(0.2f, 0.9f) animationView.repeatCount = LottieDrawable.INFINITE animationView.playAnimation() } LoadingStatus.COMPLETE -> { animationView.setMinAndMaxProgress(0.9f, 1f) animationView.repeatCount = 1 animationView.playAnimation() }}
图片
Lottie对我们而言的主要优势之一是该库支持将图片直接插入动画中。 此外,您可以插入从Internet下载的静态图像和动态图像。 现在,我将解释它是如何工作的。
对于静态图片,一切都很简单:设计人员卸载包含json和图片本身的档案。
{ "v": "5.1.13", "fr": 29.9700012207031, "ip": 0, "op": 47.0000019143492, "w": 1034, "h": 1334, "nm": " 1", "ddd": 0, "assets": [ { "id": "image_0", "w": 130, "h": 436, "u": "images/", "p": "img_0.png" }, { "id": "comp_0", "layers": [ ... ]}] }
这是img_0.png,这是您应在src / assets中放置的图片,该图片将位于动画中。
对于动态加载,使用setImageAssetDelegate方法,您必须将位图传递给该方法。 我们用Glide预加载图像,因此在打开带有动画和图片的片段的阶段,所有内容都脱离了缓存,因此一切都非常快。 这是代码:
glideLoader.loadAsBitmap(imageUrl).into(object: CustomTarget<Bitmap>() { override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) { viewAnimation.setImageAssetDelegate(object: ImageAssetDelegate { override fun fetchBitmap(asset: LottieImageAsset?): Bitmap { asset?.let { val resizeBitmap =Bitmap.createScaledBitmap(resource, it.width, it.height, true); return resizeBitmap } ?: run { return resource } } }) setAnimation(viewAnimation, animationImage) } override fun onLoadCleared(placeholder: Drawable?) {} })
性能表现
当然,最好不要在用户花费大量时间的屏幕上使用大量动画,因为这需要处理器。 根据我们的测试,某些动画上的处理器负载达到20%。 因此,这种动画的理想情况是触发一次的交互式元素。
如果某些设备上的动画放慢了速度,则有时会有所帮助
viewAnimation.useHardwareAcceleration(true)
但是,开发人员建议谨慎使用此方法,因为不同的电话以不同的方式使用硬件加速,因此,获得加速效果的相反方法是相反的。
结论
通常,使用Lottie库可以大大简化应用程序中动画的实现。
我们强调的彩票的主要优点:- 小型图书馆(300 kb)
- 跨平台解决方案iOS / Android / Web
- 从网上下载动画
- 进度管理和随处循环
- 后期效果带来的大量功能使设计人员可以实现预期的效果。
缺点:- 渲染是在主线程中完成的,而fps在应用程序中可能会大大下降。
- 解析抽奖动画可能需要花费大量时间才能处理复杂的动画。
顺便说一句,要检查动画的资源消耗程度,可以使用
Google Play的官方
Lottie应用程序。 有一个“渲染图”,您可以在其中看到渲染帧的时间,还可以看到将动画切成帧后动画的外观,或者硬件加速等的影响。