用UIKit和UIView在视图上执行iOS动画

作者 : 开心源码 本文共8701个字,预计阅读时间需要22分钟 发布时间: 2022-05-13 共224人阅读

翻译地址

本文旨在成为iOS动画的入门读物,目的是详尽地详情不同的实现方法。

鉴于该主题的广泛性,我们将在相当高的层次上简洁地涵盖每个部分。这样做的目的是通过一组选项来教育读者将动画增加到他/她的iOS应用程序中。

在我们开始探讨与IOS相关的主题之前,让我们先简单地看一看动画的速度。

60 Fps动画

通常,在视频中,每一帧由图像表示,帧速率决定在序列中翻转的图像数量。这被称为“帧每秒”或者FPS。

FPS确定在一秒钟内翻转的静止图像的数量,这实际上意味着图像/帧的数量越多,视频中显示的细节/信息就越多。这也适用于动画。

FPS通常用于确定动画的质量。有一种流行的观点认为,任何好的动画应该运行在60英尺或者更高-任何低于60 fps将感到有点不对劲。

你想看看30 FPS和60 FPS之间的区别吗?看看这个!

你注意到区别了吗?人的眼睛一定能感觉到低fps的抖动。因而,确保您所创立的任何动画都遵循运行在60 fps或者更高的基本规则,这是一个很好的实践。这让它感觉更现实,更有活力。

在查看了FPS之后,现在让我们深入研究不同的核心iOS框架,这些框架为我们提供了一种执行动画的方法

核心框架

在本节中,我们将探讨可以用于创立视图动画的IOSSDK中的框架。我们将对它们进行快速的浏览,并以相关的示例说明它们的特性集。<

UIKIT/UIVIEW动画

UIView是任何在iOS应用程序中显示内容的视图的基类。

UIKit是为我们提供UIView的框架,它已经为我们提供了少量基本的动画功能,使得开发人员可以通过更少的操作来实现更多的目标。

APIUIView.animate,由于通过提供基于块的语法中的属性值,任何视图的属性都可以很容易地被动画化。

在UIKit动画中,建议只修改UIVIew的可动画属性,否则动画可能会导致视图处于意外状态。

动画(附图:动画:完成)

此方法接受动画持续时间,这是一组需要动画化的视图的可动画属性更改。完成块在视图执行动画时提供回调。

几乎任何类型的动画,如移动,缩放,旋转,褪色,等等,在一个视图可以实现这个单一的API。

现在,考虑您想要动画一个按钮大小的变化,或者者您想要一个特定的视图放大到屏幕。这就是我们如何使用UIView.animateAPI:

let newButtonWidth: CGFloat = 60UIView.animate(withDuration: 2.0) { //1    self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth) //2    self.button.center = self.view.center //3}

我们在这里做的是:

  1. 我们称之为UIView.animate方法具备传递给它的持续时间值,该值表示在块中形容的动画应该运行多长时间。
  2. 我们设置按钮的新框架,它应该表示动画的最终状态。
  3. 我们设置按钮center它的超级视图的中心,使它保持在屏幕的中心。

上面的动画代码块应该触发按钮框架的动画,而不是当前的框架:

Width = 0, Height = 0

最后一个框架:

Width = Height = newButtonWidth

下面是动画的样子:

animateWithDuration:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion

此方法相似于动画方法的扩展,您可以在前面的API中执行所有可以执行的操作,并将少量物理行为增加到视图动画中。

例如,假如您想在上面所做的动画中实现弹簧阻尼效果,那么代码如下所示:

let newButtonWidth: CGFloat = 60UIView.animate(withDuration: 1.0, //1    delay: 0.0, //2    usingSpringWithDamping: 0.3, //3    initialSpringVelocity: 1, //4    options: UIView.AnimationOptions.curveEaseInOut, //5    animations: ({ //6        self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth)        self.button.center = self.view.center}), completion: nil)

下面是我们使用的一组参数:

  1. duration
    表示确定代码块应运行多长时间的动画持续时间。
  2. delay
    表示我们希望在动画开始之前具备的初始推迟。
  3. SpringWithDamping
    表示我们希望视图体现的弹性效果的值。数值必需在0到1之间。值越低,弹簧振荡越高。
  4. velocity
    表示动画应以何种速度启动。
  5. options
    要应用于视图动画的动画曲线类型。
  6. 最后,我们设置需要动画的按钮框架的代码块。它和以前的动画一样。

下面是用上面的动画配置动画的样子:

UIViewProperty动画

为了更好的控制动画,UIViewPropertyAnimator它为我们提供了暂停和恢复动画的方法。您可以有自己设置的定时,并使您的动画具备交互性和可中断性。这在执行动画时非常有用,这些动画也可以与客户操作交互。

经典的“滑动解锁”手势和播放器视图“解散/扩展动画”(在音乐应用程序中)是交互式动画和可中断动画的例子。您可以开始用手指移动视图,而后释放它,视图将回到原来的位置。或者者,您可以在动画期间捕捉视图并继续用手指拖动视图。

下面是一个简单的示例,说明如何使用UIViewPropertyAnimator:

let newButtonWidth: CGFloat = 60let animator = UIViewPropertyAnimator(duration:0.3, curve: .linear) { //1    self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth)    self.button.center = self.view.center}animator.startAnimation() //2

我们正在做的事情如下:

  1. 我们称之为UIViewPropertyAPI通过传递持续时间和动画曲线。
  2. 与上面的UIView.动画API不同,除非您自己指定动画,即完全控制完整的动画过程/流,否则动画不会启动。

现在,让我们假设你想要更多的控制动画。例如,您希望设计和控制动画中的每个帧。还有另一个APIanimateKeyframes。但是在我们深入研究它之前,让我们快速地看看一个框架是什么,在一个动画中。

什么是Aframe?

视图的框架更改/转换集合(从开始状态到最终状态)定义为animation动画期间视图的每个位置都被称为frame.

动画关键帧

这个API提供了一种设计动画的方法,使您可以定义具备不同时间和转换的多个动画。发布这篇文章后,API简单地将所有动画集成到一个无缝体验中。

假设我们想以随机的方式移动屏幕上的按钮。让我们看看如何使用KeyFrame动画API来做到这一点。

UIView.animateKeyframes(withDuration: 5, //1  delay: 0, //2  options: .calculationModeLinear, //3  animations: { //4    UIView.addKeyframe( //5      withRelativeStartTime: 0.25, //6      relativeDuration: 0.25) { //7        self.button.center = CGPoint(x: self.view.bounds.midX, y: self.view.bounds.maxY) //8    }    UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.25) {        self.button.center = CGPoint(x: self.view.bounds.width, y: start.y)    }    UIView.addKeyframe(withRelativeStartTime: 0.75, relativeDuration: 0.25) {        self.button.center = start    }})

详细情况如下:

  1. duration
    通过传递动画的持续时间来调用API。
  2. delay
    动画的初始推迟持续时间。
  3. options
    要应用于视图动画的动画曲线类型。
  4. animations
    块,该块接受开发人员/客户设计的所有关键帧动画。
  5. addKeyFrame
    调用API来设计每个动画。在我们的例子中,我们定义了按钮的每一个动作。我们可以有更多的这样的动画,我们需要,增加到块。
  6. relativeStartTime
    定义动画块集合中动画的启动时间。
  7. relativeDuration
    定义此特定动画的总体持续时间。
  8. center
    在我们的示例中,我们只要更改按钮的中间属性,将按钮移动到屏幕附近。

最后的动画是这样的:

共动画

任何基于UIKit的动画都是在内部转换成核心动画。因而,核心动画框架充任任何UIKit动画的支持层或者骨干。因而,所有UIKit动画API都只是以一种易于消费或者方便的方式封装了核心动画API的层。

UIKit动画API不提供对视图执行的动画的太多控制,由于它们主要用于视图的可动画属性。因而,在这种情况下,假如您想要控制动画的每一个帧,最好直接使用底层的核心动画API。或者者,UIView动画和核心动画也可以一起使用。

UIView+核心动画

让我们看看如何重新创立相同的按钮更改动画,同时使用UIView和Core动画API指定时间曲线。

我们可以用CATransaction的定时功能,它允许您指定和控制动画曲线。

让我们来看一个按钮大小变化动画的例子,它的角半径使用CATransaction的定时功能和UIView动画的组合:

let oldValue = button.frame.width/2let newButtonWidth: CGFloat = 60/* Do Animations */CATransaction.begin() //1CATransaction.setAnimationDuration(2.0) //2CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)) //3// View animations //4UIView.animate(withDuration: 1.0) {    self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth)    self.button.center = self.view.center}// Layer animationslet cornerAnimation = CABasicAnimation(keyPath: #keyPath(CALayer.cornerRadius)) //5cornerAnimation.fromValue = oldValue //6cornerAnimation.toValue = newButtonWidth/2 //7button.layer.cornerRadius = newButtonWidth/2 //8button.layer.add(cornerAnimation, forKey: #keyPath(CALayer.cornerRadius)) //9CATransaction.commit() //10

详细情况如下:

  1. begin
    表示动画代码块的开始。
  2. duration
    整体动画持续时间。
  3. curve
    表示需要应用于动画的计时曲线。
  4. UIView.animate
    我们的第一个动画改变框架的按钮。
  5. CABasicAnimation
    我们创立CABasicAnimation引用cornerRadius按钮作为键盘,由于这是我们想要的动画。相似地,假如希望对关键帧动画具备粒度级控制,则可以使用CAKeyframeAnimation班级。
  6. fromValue
    表示动画的起始值,即cornerRadius从动画必需从哪里开始的按钮的值。
  7. toValue
    表示动画的最终值,即最终值。cornerRadius动画必需结束的按钮的值。
  8. cornerRadius
    我们必需设置`cornerRadius属性的属性,以动画的最终值,否则,按钮的角半径值将在动画完成后自动恢复到其初始值。
  9. addAnimation
    通过表示动画需要执行的Keypath,我们将包含整个动画过程配置的动画对象附加到该层。
  10. commit
    表示动画代码块的结束并开始动画。

最后的动画是这样的:

这个博客是一个伟大的阅读,以帮助创立更高级的动画,由于它整齐地带您通过大多数核心动画框架API指导您通过每一步的道路。

UIKITDYNAMICS

UIKitDynamic是UIKit的物理引擎,它使您能够在UIKit控件中增加任何物理行为,如碰撞、重力、推、扣等。

UIKitDynamic动画

这是UIKitDynamicyFramework的管理类,它规范由任何给定UI控件触发的所有动画。

UIKitDynamicBehavior

它使您可以将任何物理行为增加到动画师中,从而使其能够在附在其上的视图上执行操作。

UIKitDynamic的各种行为包括:

  • UIAttachmentBehavior
  • UICollisionBehavior
  • UIFieldBehavior
  • UIGravityBehavior
  • UIPushBehavior
  • UISnapBehavior

UIKitDynamic的体系结构相似于这。请注意,项目1至5可以替换为单个视图。

让我们把少量物理行为应用到我们的按钮上。我们将看到如何将重力应用到按钮上,这样它就能给我们一种解决真实物体的感觉。

var dynamicAnimator   : UIDynamicAnimator!var gravityBehavior   : UIGravityBehavior!dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1gravityBehavior = UIGravityBehavior(items: [button]) //2dynamicAnimator.addBehavior(gravityBehavior) //3

详细情况如下:

  1. UIKitDynamicAnimator
    我们创立了一个UIKitDynamicAnimator对象,它充任执行动画的协调器。我们还传递了作为引用视图的按钮的SuperView。

  2. UIGravityBehavior
    我们创立了一个UIGravityBehavior对象,并将我们的按钮传递到注入此行为的数组元素中。

  3. addBehavior
    我们给动画师增加了重力物体。

    这将创立如下所示的动画:

注意按钮是如何从屏幕的中心(它的原始位置)掉究竟部和后面的。我们应该告诉动画师考虑屏幕底部是地面。这里是`UICollisionBehavior`进入画面。```var dynamicAnimator   : UIDynamicAnimator!var gravityBehavior   : UIGravityBehavior!var collisionBehavior : UICollisionBehavior!dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1gravityBehavior = UIGravityBehavior(items: [button]) //2dynamicAnimator.addBehavior(gravityBehavior) //3collisionBehavior = UICollisionBehavior(items: [button]) //4collisionBehavior.translatesReferenceBoundsIntoBoundary = true //5dynamicAnimator.addBehavior(collisionBehavior) //6```
  1. UICollisionBehavior
    我们创立了一个UICollisionBehavior对象并沿按钮传递,以便将行为增加到元素中。

  2. translatesReferenceBoundsIntoBoundary
    启用此属性会告诉动画师将引用视图边界作为结束,在我们的示例中,这是屏幕的底部。

  3. addBehavior
    我们在这里给动画师增加了碰撞行为。

    现在,我们的按钮应该按在地面上,静止不动,如下所示:


    挺不错的,不是吗?

现在,让我们尝试增加一个弹跳效应,使我们的对象感觉更真实。为此,我们将使用UIDynamicItemBehavior班级。

```var dynamicAnimator   : UIDynamicAnimator!var gravityBehavior   : UIGravityBehavior!var collisionBehavior : UICollisionBehavior!var bouncingBehavior  : UIDynamicItemBehavior!dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1gravityBehavior = UIGravityBehavior(items: [button]) //2dynamicAnimator.addBehavior(gravityBehavior) //3collisionBehavior = UICollisionBehavior(items: [button]) //4collisionBehavior.translatesReferenceBoundsIntoBoundary = true //5dynamicAnimator.addBehavior(collisionBehavior) //6//Adding the bounce effectbouncingBehavior = UIDynamicItemBehavior(items: [button]) //7bouncingBehavior.elasticity = 0.75 //8dynamicAnimator.addBehavior(bouncingBehavior) //9```
  1. UIDynamicItemBehavior
    我们创立了一个UIDynamicItemBehavior对象并沿按钮传递,以便将行为增加到元素中。
  2. elasticity
    数值必需在0-1之间,它代表弹性,即物体在地面上和地面上弹跳的次数。这就是魔术发生的地方–通过调整这个属性,你可以区分不同种类的物体,比方球、瓶子、硬物品等等。
  3. addBehavior
    我们在这里给动画师增加了碰撞行为。

现在,我们的按钮在触地时应该会反弹,如下所示:

这个回购是非常有用的,并显示了所有的UIKitDynamicsActions在行动中。它还提供了用于解决每一种行为的源代码。在我看来,这应该是一系列在视图上执行iOS动画的方法。

在下一节中,我们将简要详情帮助我们测量动画性能的工具。我也建议你看看优化Xcode构建的方法由于它将节省大量的开发时间。

性能调谐

在本节中,我们将研究如何测量和调优iOS动画的性能。作为iOS开发人员,您可能已经使用Xcode工具(如内存泄漏和分配)来衡量整个应用程序的性能。同样,也有少量工具可以用来衡量动画的体现。

Core Animation仪器

试试看Core Animation仪器和你应该能够看到你的应用屏幕提供的FPS。这是一个很好的方法来衡量任何动画呈现在你的iOS应用程序的性能/速度。

绘图

FPS在这个应用程序中被大大降低了,它显示的内容很重,就像图像中的阴影一样。在这种情况下,而不是直接将图像分配给UIImageView的图像属性,尝试使用CoreGraphicsAPI在上下文中分别绘制图像。当在单独的线程中而不是在主线程中执行图像解压缩逻辑时,这会过度地减少图像显示时间。

光栅化

Rasteralization是一个用于缓存复杂层信息的过程,以便这些视图在呈现时不会被重新绘制。重绘视图是FPS减少的主要起因,因而,最好对将要重复使用的视图应用栅格化。

包起来

最后,我还总结了用于iOS动画的有用资源列表。当你在iOS动画上工作时,你可能会发现这很方便。此外,您可能还会发现这套设计工具在深入研究动画之前,作为一个(设计)步骤很有帮助。

我希望我已经能够涵盖尽可能多的主题,围绕iOS动画。假如我在这篇文章中遗漏了什么,请在下面的评论部分告诉我,我很乐意做这个补充!

作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的iOS交流群:1012951431 不论你是小白还是大牛欢迎入驻 ,分享BAT,阿里面试题、面试经验,探讨技术, 大家一起交流学习成长!

另附上一份各好友收集的大厂面试题,进群可自行下载!

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 用UIKit和UIView在视图上执行iOS动画

发表回复