在上一篇博文《[UWP]在UWP平台中使用Lottie动画》中我简单介绍了一下LottieUWP项目以及如何使用它呈现Lottie动画,这篇文章里我们来讲点进阶的东西——缓存Lottie动画帧。

为什么会有这样的需求呢?

有两方面原因:

  • 直接在XAML中使用Lottie动画时,是边播放边渲染,计算量比较大,某些Lottie文件会非常吃性能!另外也会存在渲染不正确(有黑色区域)的情况,但是如果我们把每一帧缓存下来,自己控制播放的话,性能会提升很多!
  • 应用于视频合成时(给视频添加Lottie动画挂件),需要获取每一时刻的动画帧图像(UWP媒体编辑以及视频合成的相关知识也很多,有时间我会整理一下,分享点干货)。

获取Lottie动画帧

在上一篇中我们使用了LottieAnimationView控件来播放Lottie动画,其实另一个类LottieDrawable也可以完成同样的工作,并且更易扩展。

下面我们就来修改下LottieDrawable类,让它可以返回给我们某一时刻的帧图像。

LottieDrawable类中,Lottie动画的播放进度由Progress属性控制,而实际上的呈现则是使用了Win2D中的CanvasAnimatedControl控件来承载绘制目标。

这样的话,其实我们要做的就很简单了。我们可以新增一个GetCurrentFrame方法,使用CanvasRenderTarget作为绘制目标,将CanvasAnimatedControl的Draw事件中的绘制逻辑转移过来即可。

具体代码如下:

  1. /// <summary>
  2. /// 获取当前进度时的Lottie图像
  3. /// </summary>
  4. /// <param name="resourceCreator"></param>
  5. /// <param name="scaleX">横向缩放倍数</param>
  6. /// <param name="scaleY">纵向缩放倍数</param>
  7. /// <returns></returns>
  8. public CanvasBitmap GetCurrentFrame(ICanvasResourceCreator resourceCreator, float scaleX, float scaleY)
  9. {
  10. lock (this)
  11. {
  12. var width = _composition.Bounds.Width * scaleX;
  13. var height = _composition.Bounds.Height * scaleY;
  14. var commandList = new CanvasRenderTarget(resourceCreator, (float)width, (float)height, 96f);
  15. using (var session = commandList.CreateDrawingSession())
  16. {
  17. if (_bitmapCanvas == null || _bitmapCanvas.Width < width || _bitmapCanvas.Height < height)
  18. {
  19. _bitmapCanvas?.Dispose();
  20. _bitmapCanvas = new BitmapCanvas(width, height);
  21. }
  22. using (_bitmapCanvas.CreateSession(resourceCreator.Device, (float)width,
  23. (float)height, session))
  24. {
  25. _bitmapCanvas.Clear(Colors.Transparent);
  26. LottieLog.BeginSection("Drawable.Draw");
  27. if (_compositionLayer == null)
  28. {
  29. return null;
  30. }
  31. _matrix.Reset();
  32. _matrix = MatrixExt.PreScale(_matrix, scaleX, scaleY);
  33. _compositionLayer.Draw(_bitmapCanvas, _matrix, _alpha);
  34. LottieLog.EndSection("Drawable.Draw");
  35. }
  36. }
  37. return commandList;
  38. }
  39. }

有一点要注意的是这里的绘制目标使用了CanvasRenderTarget,切勿使用CanvasCommandList,区别在于CanvasRenderTarget有固定大小的尺寸,而CanvasCommandList则没有固定的尺寸(实际上时无限大的),使用CanvasCommandList作为绘制目标将会引起某些Lottie动画绘制时丢失部分内容,具体可参见我在LottieUWP项目上提的这个Issue

缓存Lottie动画帧

有了上面添加的GetCurrentFrame方法后,我们就可以通过修改Progress来获取Lottie动画中每一时刻的帧图像了。

我编写了一个缓存Lottie动画帧的方法:

  1. protected List<CanvasBitmap> CacheLottieFrames;
  2. /// <summary>
  3. /// 缓存Lottie动画帧
  4. /// </summary>
  5. /// <param name="width">缓存图像的宽</param>
  6. /// <param name="height">缓存图像的高</param>
  7. /// <param name="frameRate">缓存的帧率</param>
  8. /// <returns></returns>
  9. private async Task InitLottieFrame(double width, double height, int frameRate)
  10. {
  11. await Task.Run(() =>
  12. {
  13. lock (_lockObj)
  14. {
  15. if (lottieDrawable != null)
  16. {
  17. var duration = lottieDrawable.Composition.Duration;
  18. var scaleX = width / lottieDrawable.Composition.Bounds.Width;
  19. var scaleY = height / lottieDrawable.Composition.Bounds.Height;
  20. var timeGap = 1d / frameRate;
  21. CacheLottieFrames = new List<CanvasBitmap>();
  22. var device = CanvasDevice.GetSharedDevice();
  23. for (var i = 0d; i < duration; i += timeGap)
  24. {
  25. lottieDrawable.Progress = (float)(i / duration);
  26. var renderTarget =
  27. new CanvasRenderTarget(device, (float)CanvasWidth, (float)CanvasHeight, 96f);
  28. using (var session = renderTarget.CreateDrawingSession())
  29. {
  30. session.Clear(Colors.Transparent);
  31. var effectImg = lottieDrawable.GetCurrentFrame(device, (float)scaleX, (float)scaleY);
  32. if (effectImg != null)
  33. session.DrawImage(effectImg);
  34. }
  35. CacheLottieFrames.Add(renderTarget);
  36. }
  37. }
  38. }
  39. });
  40. }

我们也可以在LottieDrawable.Composition中获取到帧的总数量以及帧率,以此为依据来获取帧,但是我在这个方法里没有使用,因为我想依据传入的帧率来控制获取的帧数量,避免缓存多余的帧占据内存空间。

结尾

有关于UWP使用Lottie动画的相关博文到这里就结束了,这段时间接触下来,我的感受是Lottie动画真的挺好玩效果也很棒。在LottieFiles网站大家可以找到各种有趣好玩的Lottie动画,当然有能力的也可以自己制作。

本篇博客到此结束!谢谢大家阅读!

[UWP]缓存Lottie动画帧的更多相关文章

  1. [UWP]在UWP平台中使用Lottie动画

    最近QQ影音久违的更新了,因为记得QQ影音之前体验还算不错(FFmepg的事另说),我也第一时间去官网下载体验了一下,结果发现一些有趣的事情. 是的,你没看错,QQ影音主界面上这个动画效果是使用Lot ...

  2. CSS3的自定义动画帧

    CSS3新增的动画帧非常绚丽,可以简单实现一些动画效果,目前除IE外各大主流浏览器都支持 本文演示三个:transform: scale3d(x, y, z)-缩放;.transform: trans ...

  3. U3D 动画帧事件问题

    测试版本U3D5.4. 1,为一个模型导入外部动画.为动画剪辑attack在某帧添加event,事件为 public void OnAttackEvent(){},函数体不做任何事情. 结果发现,在动 ...

  4. 【转】CSS3动画帧数科学计算法

    本文来源于:财付通TID 原作者:bboy90 总结都浓缩在这个工具里了,想知道工具的地址或想窥探工具诞生的趣事请往下看 . —————————————————————–     华丽丽的开篇     ...

  5. Unity 3D 动画帧事件

    前几天在项目开发中碰到一个这样的需求,RPG游戏中,特效和动画播放不同步的.假如主角在攻击NPC时,先实例化特效,后播放动画.动画毕竟是有一个时间长度的.等到动画播放攻击挥刀的那一瞬间时,特效可能早就 ...

  6. Android之Lottie动画详解

    文章大纲 一.Lottie介绍二.Lottie实战三.项目源码下载四.参考文章   一.Lottie介绍 1. 什么是Lottie   Lottie是Android和iOS的移动库,用于解析Adobe ...

  7. 程序员也想改 Lottie 动画?是的!

    一.前言 Hi,大家好,我是承香墨影! Lottie 是 Airbnb 开源的一套跨平台的完整的动画效果解决方案,用过都说好.完全解耦开发人员和设计师,让设计师设计的动画,在程序中无缝还原,真是一旦拿 ...

  8. Lottie 动画里有图片怎么办?设计师小姐姐也能帮你减少开发量!

    一.序 Hi,大家好,我是承香墨影! Lottie 是 Airbnb 开源的一套跨平台的完整解决方案,设计师只需要使用 After Effectes (之后简称 AE)设计出动画之后,使用 Lotti ...

  9. HTML5游戏中动画帧的概念理解

    最近在弄一个HTML5游戏,在学习过程中,总结出这个帧结构. HTML5游戏最重要也就是对帧的理解. 容器:Canvas 一个画布 sprite:一个canvas上有多个动画,每个动画对象就是一个An ...

随机推荐

  1. epoll的LT和ET(转)

    1 socket IO事件 1.1 读事件 读事件:句柄从不可读变成可读,或者句柄写缓冲区有新的数据进来且超过SO_RCVLOWAT. 常见的产生读事件有如下几种: socket有一个未清除的错误.如 ...

  2. 更改mysql 和jinkins目录

    更改MySQL数据目录 1.修改my.cnf,注销原datadir,增加新的数据目录 #datadir=/var/lib/mysqldatadir=/mysql-data/mysql 2.修改启动脚本 ...

  3. SpringBoot +Pom.xml工程资源文件配置

    继承spring-boot-starter-parent 要成为一个spring boot项目,首先就必须在pom.xml中继承spring-boot-starter-parent,同时指定其版本 & ...

  4. join() ---- 使用四种不同的分隔符连接数组元素

    var a = ['Wind', 'Rain', 'Fire']; var myVar1 = a.join(); // myVar1的值变为"Wind,Rain,Fire" var ...

  5. Python中的logging模块【转】https://www.cnblogs.com/yelin/p/6600325.html

    [转]https://www.cnblogs.com/yelin/p/6600325.html 基本用法 下面的代码展示了logging最基本的用法. 1 # -*- coding: utf-8 -* ...

  6. Github(远程仓库) 2

    远程仓库之前就添加好了 今天弄了简单的查看远程库,提取远程库,在线修改以及本地更新修改,推送到远程仓库,删除远程仓库,参考http://www.runoob.com/git/git-remote-re ...

  7. Log4J2用法

    一.    关于Log4J 2015年5月,Apache宣布Log4J 1.x 停止更新.最新版为1.2.17. 如今,Log4J 2.x已更新至2.7. 官方网址:http://logging.ap ...

  8. Why is it called “armature” instead of “skeleton”? or perhaps “rig”?

    Great question, I’ve always assumed armature/skeleton to be the same thing, here’s a quote from an a ...

  9. [leetcode]49. Group Anagrams变位词归类

    Given an array of strings, group anagrams together. Example: Input: ["eat", "tea" ...

  10. day 32 JavaScript

    1.1. JavaScript介绍 HTML:定义网页的结构 CSS:美化网页 JavaScript:实现用户交互: 1.1.2 JavaScript特点 n  安全性较高 n  跨平台,兼容性好 1 ...