- 端游游戏开发
[UWP]缓存Lottie动画帧
时间:2018-12-30 10:35:52 作者:06评比 来源:06评比 查看:12 评论:0内容摘要:这篇文章里我们来讲点进阶的东西——缓存Lottie动画帧。为什么会有这样的需求呢?有两方面原因:直接在XAML中使用Lottie动画时,是边播放边渲染,计算量比较大,某些Lottie文件会非常吃性能!另外也会存在渲染不正确(有黑色区域)的情况,但是如果我们...这篇文章里我们来讲点进阶的东西——缓存Lottie动画帧。为什么会有这样的需求呢?
有两方面原因:
- 直接在XAML中使用Lottie动画时,是边播放边渲染,计算量比较大,某些Lottie文件会非常吃性能!另外也会存在渲染不正确(有黑色区域)的情况,但是如果我们把每一帧缓存下来,自己控制播放的话,性能会提升很多!
- 应用于视频合成时(给视频添加Lottie动画挂件),需要获取每一时刻的动画帧图像(UWP媒体编辑以及视频合成的相关知识也很多,有时间我会整理一下,分享点干货)。
获取Lottie动画帧#
在上一篇中我们使用了
LottieAnimationView
控件来播放Lottie动画,其实另一个类LottieDrawable
也可以完成同样的工作,并且更易扩展。下面我们就来修改下
LottieDrawable
类,让它可以返回给我们某一时刻的帧图像。在
LottieDrawable
类中,Lottie动画的播放进度由Progress
属性控制,而实际上的呈现则是使用了Win2D中的CanvasAnimatedControl
控件来承载绘制目标。这样的话,其实我们要做的就很简单了。我们可以新增一个
GetCurrentFrame
方法,使用CanvasRenderTarget
作为绘制目标,将CanvasAnimatedControl
的Draw事件中的绘制逻辑转移过来即可。具体代码如下:
/// <summary> /// 获取当前进度时的Lottie图像 /// </summary> /// <param name="resourceCreator"></param> /// <param name="scaleX">横向缩放倍数</param> /// <param name="scaleY">纵向缩放倍数</param> /// <returns></returns> public CanvasBitmap GetCurrentFrame(ICanvasResourceCreator resourceCreator, float scaleX, float scaleY) { lock (this) { var width = _composition.Bounds.Width * scaleX; var height = _composition.Bounds.Height * scaleY; var commandList = new CanvasRenderTarget(resourceCreator, (float)width, (float)height, 96f); using (var session = commandList.CreateDrawingSession()) { if (_bitmapCanvas == null || _bitmapCanvas.Width < width || _bitmapCanvas.Height < height) { _bitmapCanvas?.Dispose(); _bitmapCanvas = new BitmapCanvas(width, height); } using (_bitmapCanvas.CreateSession(resourceCreator.Device, (float)width, (float)height, session)) { _bitmapCanvas.Clear(Colors.Transparent); LottieLog.BeginSection("Drawable.Draw"); if (_compositionLayer == null) { return null; } _matrix.Reset(); _matrix = MatrixExt.PreScale(_matrix, scaleX, scaleY); _compositionLayer.Draw(_bitmapCanvas, _matrix, _alpha); LottieLog.EndSection("Drawable.Draw"); } } return commandList; } }
有一点要注意的是这里的绘制目标使用了
CanvasRenderTarget
,切勿使用CanvasCommandList
,区别在于CanvasRenderTarget
有固定大小的尺寸,而CanvasCommandList
则没有固定的尺寸(实际上时无限大的),使用CanvasCommandList
作为绘制目标将会引起某些Lottie动画绘制时丢失部分内容,具体可参见我在LottieUWP项目上提的这个Issue 。缓存Lottie动画帧#
有了上面添加的
GetCurrentFrame
方法后,我们就可以通过修改Progress
来获取Lottie动画中每一时刻的帧图像了。我编写了一个缓存Lottie动画帧的方法:
protected List<CanvasBitmap> CacheLottieFrames; /// <summary> /// 缓存Lottie动画帧 /// </summary> /// <param name="width">缓存图像的宽</param> /// <param name="height">缓存图像的高</param> /// <param name="frameRate">缓存的帧率</param> /// <returns></returns> private async Task InitLottieFrame(double width, double height, int frameRate) { await Task.Run(() => { lock (_lockObj) { if (lottieDrawable != null) { var duration = lottieDrawable.Composition.Duration; var scaleX = width / lottieDrawable.Composition.Bounds.Width; var scaleY = height / lottieDrawable.Composition.Bounds.Height; var timeGap = 1d / frameRate; CacheLottieFrames = new List<CanvasBitmap>(); var device = CanvasDevice.GetSharedDevice(); for (var i = 0d; i < duration; i += timeGap) { lottieDrawable.Progress = (float)(i / duration); var renderTarget = new CanvasRenderTarget(device, (float)CanvasWidth, (float)CanvasHeight, 96f); using (var session = renderTarget.CreateDrawingSession()) { session.Clear(Colors.Transparent); var effectImg = lottieDrawable.GetCurrentFrame(device, (float)scaleX, (float)scaleY); if (effectImg != null) session.DrawImage(effectImg); } CacheLottieFrames.Add(renderTarget); } } } }); }
我们也可以在
LottieDrawable.Composition
中获取到帧的总数量以及帧率,以此为依据来 获取帧,但是我在这个方法里没有使用,因为我想依据传入的帧率来控制获取的帧数量,避免缓存多余的帧占据内存空间。结尾#
有关于UWP使用Lottie动画的相关博文到这里就结束了,这段时间接触下来,我的感受是Lottie动画真的挺好玩效果也很棒。在LottieFiles网站大家可以找到各种有趣好玩的Lottie动画,当然有能力的也可以自己制作。
- 相关文章
- 本类更新
-
3-8使用ASP.NET Core2.2创建WebApp
-
1-1surging 微服务引擎 1.0 正式发布
-
12-30[UWP]缓存Lottie动画帧
-
12-28.NetCore WebApi + Vue +MySql搭建博客
-
12-26采用异步来实现重新连接服务器或者重新启动服务
-
12-24WPF实战案例-数据代理
-
12-22C# 输入一个整数,求质因数
-
12-20WPF实现可视化控件打印及打印预览
-
12-18Asp.Net Core下的两种路由配置方式
-
12-16status 返回当前请求的http状态码
-
- 本类推荐
- 本类排行