UIDynamics, UIKit 或 OpenGL? 3 种 iOS 动画实现分析

594 查看

你有没想过,乔治·卢卡斯的太空史诗歌剧,其实,可以在 iOS 上实现?在银河系中黑暗与光明双方之间的永恒战役中,我们得到启发,并创建具有星球大战人物特色的梦幻般的 UI 动画。

创作我们自己的星球大战续集,对于我们最强的两种原力:设计和开发,都是个挑战。

iOS animation for user profile. Star Wars

设计星球大战动画

by Kostya Trundayev

在我开始制作动画的时候,我想对标准开关控件创作一种独一无二的交互逻辑,并扩展影响到整个屏幕。我想到了一个有趣的想法,让用户通过点击该开关,进行两种不同的外观的切换。但我该使用什么界面来让两种设定显得有意义呢?

Star Wars animation creation

我记得星球大战,尤其是星球大战系列游戏,用户可以加入光明或黑暗的一方。天行者与黑武士。光明与黑暗。没错!这个矛盾人格的想法是多么出色,实在无法用言语形容。

我已经花了几个小时研究界面,我为每个设定档创建了两种图片拼贴,并绘制自己的界面。我使用 Photoshop 创建设定档,然后在 Adobe After Effects 中添加动画。

在两种屏幕都准备好了后,我觉得若发布在 Dribbble 它们看起太朴素了。我瞥了一眼屏幕中的黑武士,我终于想到了!画面中黑武士试图用他的手触碰十字星座。我想,“要是屏幕不只是接近,而是碎成小块,就像被原力击中一样?”这听起来很酷!我研究了在 After Effects 中如何实现,并做出了正如我想象的效果。我使用了粉碎效果,它能让我通过运用许多不同的设置实现摇摇欲坠的效果。

Star Wars animation

所以,剩下来唯一要做的事情是循环动画,因为该组件在动画结束的后,没有可供用户着陆的屏幕,并且从那里可以通过设定档的设置回到屏幕。这就是为什么我用星球大战标志创建第三个屏幕的原因,一个“设置你的个人资料”的按钮和群星璀璨的天空。我在 CC 球状动作特效的帮助下制作了该星空。

我将视频放入设备模型中,并为 Dribbble 做了个短片。但故事还没有结束。你还是可以学到更多内容的,因为伟大的设计加上天才的开发才是真正的原力觉醒。

使用 Swift 开发星球大战动画

by Artem Sydorenko

有两件事情在星球大战动画中似乎很难实现(在 Github 上浏览):在主屏幕中满天飞的星星和碎成片片的视图。我在 CAEmitterLayer 的帮助下解决了第一个挑战,它是一个提供粒子发射系统的类。然后,我有一段相当艰苦的时间,就是试图将视图破碎的 4000 个碎片以不同的方向降落。

如何将星球大战击成碎片

为了将 UIView 打破成碎片,我用了下面的方法:snapshotViewAfterScreenUpdates()resizableSnapshotViewFromRect (afterScreenUpdates:withCapInsets:)。我也使用了中间快照,它能让我更快创建创建小碎片(从快照创建快照比从原来视图制作非常小的快照要快得多):

有 3 种方式可以实现向星球大战那样的动画:通过使用 UIDynamicsCore Animation (UIKit)OpenGL。我们用了全部这些方法来制作了动画,让我们来看看结果。

扩展阅读:如何在 iOSAndroid 上创建铡刀菜单动画。

用 UIDymanics 制作动画

UIDynamics 是我们第一只小白鼠。我认为这个工具可以帮我实现物体自然下落的效果。它是这样子的:

但是事实证明物体物理运动计算是很耗 CPU 的(我们有大量的物体)。我们不得不同时移动 4000 个对象,UIDynamics 很难维持这样的负荷。

下面是我们的计算结果:

UIDymanics for creating user profile animation

使用 UIKit (Core Animation) 制作动画

由于使用 UIDynamics 制作星球大战动画是低效的,我决定使用 UIView 将动画重写一遍:

在这种情况下,只有当我们将动画切割成碎片 CPU 才受到影响,这样会在动画开始时有个小延迟。但是,由于在 GPU 负荷,FPS(帧每秒)不能同时显示超过 1500 个视图。FPS 会被降到 26,但不能使动画达到我想要的 60 FPS 流畅度。

Animating Star Wars with UIKit

由于我们仍不能得到满意的结果,我们决定使用 OpenGL 制作星球大战动画。

使用 OpenGL 制作动画

多数 iOS 教程都是用 Objective-C 设计的,所以我决定用它来开始,如果成功实现,我会使用 Swift 再重写一遍动画(我做到了)。

结果是惊人的,我可以在 iPhone 6 上以 60 帧每秒播放视图碎片动画,而且没有任何中断或延迟。

我想:如果我把动画切碎成 40,000 块而不是 4,000 块呢?OpenGL 能应对这种负荷吗?通过实验该数字,我得到了 4 FPS。为了跟踪代码表现不佳的部分,我用 time profiler 来运行动画。这能让我看到负载并显示花费最长时间实现的方法。

在 time profiler 下,动画运行在 23 FPS,但这很容易解释。Time profiler 执行的是发布配置,这意味着它可以优化正在编译的代码。

我重写了关键代码(我将 BlowSprite 的改成结构体并替换了映射周期)后,我可以在发布版本配置上达到 60 FPS。我让动画快了两倍有多!(在没有编译优化的调试配置上, 我得到 11 FPS)。

Using OpenGL to animate user profile interface

扩展阅读:如何开发 Android 上的 Instagram 视频

在实现了 3 种类型的动画后,我们可以从下面的统计图看到 UIDynamicsUIKit (Core Animation)OpenGL 的实验结果。只有 OpenGL 动画可以应付负载需求,所以选择他来实现我们的组件。

我们对 CPU 的实验结果如下所示。

CPU performance measuring for UIDynamics, UIKit and OpenGL

在帧每秒的表现上:

FPS performance results for UIDynamics, UIKit and OpenGL

如何在你的项目中添加星球大战?

单实现 UIViewControllerTransitioningDelegate 类,可以返回我们的动画构成方法 animationControllerForDismissedController,然后赋值给 viewController 你想排除的 transitioningDelegate

如何自定义组件

在星球大战动画中有两件事情你可以自定义:持续时间和碎片尺寸。让我们来看看你可以怎么做。

持续时间的部分代码:

碎片尺寸,改变各部分点的尺寸:

你可以在这些地方查阅我们的星球大战组件:

愿原力与你同在!