在 UIView 中动画图像

Posted

技术标签:

【中文标题】在 UIView 中动画图像【英文标题】:Animating images in a UIView 【发布时间】:2020-07-05 23:37:32 【问题描述】:

我有一个由 SwiftUI 提供的 UIViewRepresentable 视图,我在其中创建了三到四个相当复杂的图形对象,并以精确的速度在视图中移动它们。我使用 CADisplayLink 来计算每个新帧这些对象应该移动多少。

我的帧速率不是很好,所以我想我会尝试通过以编程方式创建 UIImage 来缓存图像块,并将其缓存在主内存中。这很好用,我可以在单独的线程中创建新的 UIImage 对象,但帧速率实际上比根据需要绘制所有内容要慢一些。

视图包含三四个这样的东西,我有一个后台任务,创建近期需要的 UIIMages,并重新使用已经滚出屏幕的 UIImages,所以我的内存利用率相对最小 - 如有必要,我可以创建一个大型合成图像,使用 ScrollView 以编程方式滚动,但我担心这种方法会占用更多内存。

有没有更好的方法来缓存视图的可重用块并在视图中为它们设置动画?当然,我想尽可能多地卸载到 GPU。创建 UIImage 是正确的方法吗?创建 CALayer 或其他位图表示会更好吗?我应该把这些东西放到 ScrollView 中吗?我应该创建一个可以由系统动画的视图,而不是使用 CADisplayLink 计时逐帧动画吗? (我需要能够立即取消动画)。

我很欣赏这可能不是一个只有一个正确答案的简单代码问题,但我希望能朝着正确的方向前进,谢谢!

【问题讨论】:

【参考方案1】:

Apple 已经开发了多种框架,每个框架都可能是此应用程序的合适选择。软件设计人员的重要选择之一是为特定应用程序选择合适的框架。

Apple 倾向于记录单个框架而不讨论它们与其他框架的关系,这就是为什么我认为在选择架构时咨询整个开发社区是很有价值的。

在这种情况下,一些位图表示缓存在主内存中,一些在图形卡的视频内存中(仅限 Mac OS),还有一些在移动设备的后备存储中用于视图。从 Apple 的文档中,特定类的实际实现方式并不总是很明显。

因此,我对几种不同的方法进行了基准测试(当然是为相同的内容制作动画):

在内存中创建 UIImage 对象数组,并通过 CADisplayLink 绘制它们产生大约 6 Hz 的帧速率。 创建一个 CALayer 并使用 CADisplayLink 对其进行定位会产生 120 Hz 的帧速率。

我不声称知道 UIImage 光栅化是如何处理的,但我猜测它使用主 CPU 处理器和主内存发生,并且图像在主绘图循环中被复制到图形内存中。显然,其中一些任务被传递给了 Metal,但它实际上是如何实现的并不明显。

我猜测 CALayers 被认为不需要缩放和光栅化,并且视口更改由 GPU 处理,几乎没有 CPU 干预。

我仍然不知道是否最好启动动画并在必要时对其进行调整,或者明确定位 CALayer 是否最好。但是我使用的方法产生了良好的帧速率和低 CPU 使用率,所以我将把它作为一个学术问题留给读者。

我发现了一些关于这个主题的有用文章:

https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreAnimation_guide/CoreAnimationBasics/CoreAnimationBasics.html#//apple_ref/doc/uid/TP40004514-CH2-SW3

https://blog.spacemanlabs.com/2011/07/calayers-v-cglayers-or-which-layer-player/

add UIImage in CALayer

https://www.raywenderlich.com/10317653-calayer-tutorial-for-ios-getting-started

【讨论】:

以上是关于在 UIView 中动画图像的主要内容,如果未能解决你的问题,请参考以下文章

使用图像为 UIView 的位置和大小设置动画的正确方法(此方法在 Xcode 6 中中断)?

来自 UITableView 的动画 UIView

android手机默认浏览器,使用canvas画图会重复出现两次图像以及动画效果

如何在代码中调用 UIView 动画

如何在 Swift 中多次为 UIView 的翻转设置动画

在视图控制器之间切换时,图像旋转动画会加速吗