本文旨在成为iOS动画的入门读物,目的是详尽地介绍不一样的实现方法。php
鉴于该主题的普遍性,咱们将在至关高的层次上简洁地涵盖每一个部分。这样作的目的是经过一组选项来教育读者将动画添加到他/她的iOS应用程序中。ios
在咱们开始讨论与IOS相关的主题以前,让咱们先简单地看一看动画的速度。git
一般,在视频中,每一帧由图像表示,帧速率决定在序列中翻转的图像数量。这被称为“帧每秒”或FPS。github
FPS肯定在一秒钟内翻转的静止图像的数量,这实际上意味着图像/帧的数量越多,视频中显示的细节/信息就越多。这也适用于动画。swift
FPS一般用于肯定动画的质量。有一种流行的观点认为,任何好的动画应该运行在60英尺或更高-任何低于60 fps将感到有点不对劲。数组
你想看看30 FPS和60 FPS之间的区别吗?看看这个!xcode
你注意到区别了吗?人的眼睛确定能感受到低fps的抖动。所以,确保您所建立的任何动画都遵循运行在60 fps或更高的基本规则,这是一个很好的实践。这让它感受更现实,更有活力。缓存
在查看了FPS以后,如今让咱们深刻研究不一样的核心iOS框架,这些框架为咱们提供了一种执行动画的方法bash
在本节中,咱们将讨论能够用于建立视图动画的IOSSDK中的框架。咱们将对它们进行快速的浏览,并以相关的示例说明它们的特性集。<框架
UIView是任何在iOS应用程序中显示内容的视图的基类。
UIKit是为咱们提供UIView的框架,它已经为咱们提供了一些基本的动画功能,使得开发人员能够经过更少的操做来实现更多的目标。
APIUIView.animate
,由于经过提供基于块的语法中的属性值,任何视图的属性均可以很容易地被动画化。
在UIKit动画中,建议只修改UIVIew的可动画属性,不然动画可能会致使视图处于意外状态。
此方法接受动画持续时间,这是一组须要动画化的视图的可动画属性更改。完成块在视图执行动画时提供回调。
几乎任何类型的动画,如移动,缩放,旋转,褪色,等等,在一个视图能够实现这个单一的API。
如今,考虑您想要动画一个按钮大小的变化,或者您想要一个特定的视图放大到屏幕。这就是咱们如何使用UIView.animate
API:
let newButtonWidth: CGFloat = 60
UIView.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
}
复制代码
咱们在这里作的是:
UIView.animate
方法具备传递给它的持续时间值,该值表示在块中描述的动画应该运行多长时间。center
它的超级视图的中心,使它保持在屏幕的中心。上面的动画代码块应该触发按钮框架的动画,而不是当前的框架:
Width = 0, Height = 0
最后一个框架:
Width = Height = newButtonWidth
下面是动画的样子:
此方法相似于动画方法的扩展,您能够在前面的API中执行全部能够执行的操做,并将一些物理行为添加到视图动画中。
例如,若是您想在上面所作的动画中实现弹簧阻尼效果,那么代码以下所示:
let newButtonWidth: CGFloat = 60
UIView.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)
复制代码
下面是咱们使用的一组参数:
duration
表示肯定代码块应运行多长时间的动画持续时间。delay
表示咱们但愿在动画开始以前具备的初始延迟。SpringWithDamping
表示咱们但愿视图表现的弹性效果的值。数值必须在0到1之间。值越低,弹簧振荡越高。velocity
表示动画应以何种速度启动。options
要应用于视图动画的动画曲线类型。下面是用上面的动画配置动画的样子:
为了更好的控制动画,UIViewPropertyAnimator
它为咱们提供了暂停和恢复动画的方法。您能够有自定义的定时,并使您的动画具备交互性和可中断性。这在执行动画时很是有用,这些动画也能够与用户操做交互。
经典的“滑动解锁”手势和播放器视图“解散/扩展动画”(在音乐应用程序中)是交互式动画和可中断动画的例子。您能够开始用手指移动视图,而后释放它,视图将回到原来的位置。或者,您能够在动画期间捕捉视图并继续用手指拖动视图。
下面是一个简单的示例,说明如何使用UIViewPropertyAnimator
:
let newButtonWidth: CGFloat = 60
let 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
复制代码
咱们正在作的事情以下:
UIViewProperty
API经过传递持续时间和动画曲线。如今,让咱们假设你想要更多的控制动画。例如,您但愿设计和控制动画中的每一个帧。还有另外一个APIanimateKeyframes
。可是在咱们深刻研究它以前,让咱们快速地看看一个框架是什么,在一个动画中。
frame
?视图的框架更改/转换集合(从开始状态到最终状态)定义为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
}
})
复制代码
详细状况以下:
duration
经过传递动画的持续时间来调用API。delay
动画的初始延迟持续时间。options
要应用于视图动画的动画曲线类型。animations
块,该块接受开发人员/用户设计的全部关键帧动画。addKeyFrame
调用API来设计每一个动画。在咱们的例子中,咱们定义了按钮的每个动做。咱们能够有更多的这样的动画,咱们须要,添加到块。relativeStartTime
定义动画块集合中动画的启动时间。relativeDuration
定义此特定动画的整体持续时间。center
在咱们的示例中,咱们只需更改按钮的中间属性,将按钮移动到屏幕周围。最后的动画是这样的:
任何基于UIKit的动画都是在内部转换成核心动画。所以,核心动画框架充当任何UIKit动画的支持层或骨干。所以,全部UIKit动画API都只是以一种易于消费或方便的方式封装了核心动画API的层。
UIKit动画API不提供对视图执行的动画的太多控制,由于它们主要用于视图的可动画属性。所以,在这种状况下,若是您想要控制动画的每个帧,最好直接使用底层的核心动画API。或者,UIView动画和核心动画也能够一块儿使用。
让咱们看看如何从新建立相同的按钮更改动画,同时使用UIView和Core动画API指定时间曲线。
咱们能够用CATransaction
的定时功能,它容许您指定和控制动画曲线。
让咱们来看一个按钮大小变化动画的例子,它的角半径使用CATransaction
的定时功能和UIView动画的组合:
let oldValue = button.frame.width/2
let newButtonWidth: CGFloat = 60
/* Do Animations */
CATransaction.begin() //1
CATransaction.setAnimationDuration(2.0) //2
CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)) //3
// View animations //4
UIView.animate(withDuration: 1.0) {
self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth)
self.button.center = self.view.center
}
// Layer animations
let cornerAnimation = CABasicAnimation(keyPath: #keyPath(CALayer.cornerRadius)) //5
cornerAnimation.fromValue = oldValue //6
cornerAnimation.toValue = newButtonWidth/2 //7
button.layer.cornerRadius = newButtonWidth/2 //8
button.layer.add(cornerAnimation, forKey: #keyPath(CALayer.cornerRadius)) //9
CATransaction.commit() //10
复制代码
详细状况以下:
begin
表示动画代码块的开始。duration
总体动画持续时间。curve
表示须要应用于动画的计时曲线。UIView.animate
咱们的第一个动画改变框架的按钮。CABasicAnimation
咱们建立CABasicAnimation
引用cornerRadius
按钮做为键盘,由于这是咱们想要的动画。相似地,若是但愿对关键帧动画具备粒度级控制,则可使用CAKeyframeAnimation
班级。fromValue
表示动画的起始值,即cornerRadius
从动画必须从哪里开始的按钮的值。toValue
表示动画的最终值,即最终值。cornerRadius
动画必须结束的按钮的值。cornerRadius
咱们必须设置`cornerRadius属性的属性,以动画的最终值,不然,按钮的角半径值将在动画完成后自动恢复到其初始值。addAnimation
经过表示动画须要执行的Keypath,咱们将包含整个动画过程配置的动画对象附加到该层。commit
表示动画代码块的结束并开始动画。最后的动画是这样的:
这个博客是一个伟大的阅读,以帮助建立更高级的动画,由于它整齐地带您经过大多数核心动画框架API指导您经过每一步的道路。
UIKitDynamic是UIKit的物理引擎,它使您可以在UIKit控件中添加任何物理行为,如碰撞、重力、推、扣等。
这是UIKitDynamicyFramework的管理类,它规范由任何给定UI控件触发的全部动画。
它使您能够将任何物理行为添加到动画师中,从而使其可以在附在其上的视图上执行操做。
UIKitDynamic的各类行为包括:
UIAttachmentBehavior
UICollisionBehavior
UIFieldBehavior
UIGravityBehavior
UIPushBehavior
UISnapBehavior
UIKitDynamic的体系结构相似于这。请注意,项目1至5能够替换为单个视图。
让咱们把一些物理行为应用到咱们的按钮上。咱们将看到如何将重力应用到按钮上,这样它就能给咱们一种处理真实物体的感受。
var dynamicAnimator : UIDynamicAnimator!
var gravityBehavior : UIGravityBehavior!
dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1
gravityBehavior = UIGravityBehavior(items: [button]) //2
dynamicAnimator.addBehavior(gravityBehavior) //3
复制代码
详细状况以下:
UIKitDynamicAnimator
咱们建立了一个UIKitDynamicAnimator
对象,它充当执行动画的协调器。咱们还传递了做为引用视图的按钮的SuperView。
UIGravityBehavior
咱们建立了一个UIGravityBehavior
对象,并将咱们的按钮传递到注入此行为的数组元素中。
addBehavior
咱们给动画师添加了重力物体。
这将建立以下所示的动画:
注意按钮是如何从屏幕的中心(它的原始位置)掉到底部和后面的。
咱们应该告诉动画师考虑屏幕底部是地面。这里是UICollisionBehavior
进入画面。
var dynamicAnimator : UIDynamicAnimator!
var gravityBehavior : UIGravityBehavior!
var collisionBehavior : UICollisionBehavior!
dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1
gravityBehavior = UIGravityBehavior(items: [button]) //2
dynamicAnimator.addBehavior(gravityBehavior) //3
collisionBehavior = UICollisionBehavior(items: [button]) //4
collisionBehavior.translatesReferenceBoundsIntoBoundary = true //5
dynamicAnimator.addBehavior(collisionBehavior) //6
复制代码
UICollisionBehavior
咱们建立了一个UICollisionBehavior
对象并沿按钮传递,以便将行为添加到元素中。
translatesReferenceBoundsIntoBoundary
启用此属性会告诉动画师将引用视图边界做为结束,在咱们的示例中,这是屏幕的底部。
addBehavior
咱们在这里给动画师添加了碰撞行为。
如今,让咱们尝试添加一个弹跳效应,使咱们的对象感受更真实。为此,咱们将使用UIDynamicItemBehavior
班级。
```
var dynamicAnimator : UIDynamicAnimator!
var gravityBehavior : UIGravityBehavior!
var collisionBehavior : UICollisionBehavior!
var bouncingBehavior : UIDynamicItemBehavior!
dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1
gravityBehavior = UIGravityBehavior(items: [button]) //2
dynamicAnimator.addBehavior(gravityBehavior) //3
collisionBehavior = UICollisionBehavior(items: [button]) //4
collisionBehavior.translatesReferenceBoundsIntoBoundary = true //5
dynamicAnimator.addBehavior(collisionBehavior) //6
//Adding the bounce effect
bouncingBehavior = UIDynamicItemBehavior(items: [button]) //7
bouncingBehavior.elasticity = 0.75 //8
dynamicAnimator.addBehavior(bouncingBehavior) //9
```
复制代码
UIDynamicItemBehavior
咱们建立了一个UIDynamicItemBehavior
对象并沿按钮传递,以便将行为添加到元素中。elasticity
数值必须在0-1之间,它表明弹性,即物体在地面上和地面上弹跳的次数。这就是魔术发生的地方--经过调整这个属性,你能够区分不一样种类的物体,好比球、瓶子、硬物品等等。addBehavior
咱们在这里给动画师添加了碰撞行为。如今,咱们的按钮在触地时应该会反弹,以下所示:
这个回购是很是有用的,并显示了全部的UIKitDynamicsActions在行动中。它还提供了用于处理每一种行为的源代码。在我看来,这应该是一系列在视图上执行iOS动画的方法。
在下一节中,咱们将简要介绍帮助咱们测量动画性能的工具。我也建议你看看优化Xcode构建的方法由于它将节省大量的开发时间。
在本节中,咱们将研究如何测量和调优iOS动画的性能。做为iOS开发人员,您可能已经使用Xcode工具(如内存泄漏和分配)来衡量整个应用程序的性能。一样,也有一些工具能够用来衡量动画的表现。
Core Animation
仪器试试看Core Animation
仪器和你应该可以看到你的应用屏幕提供的FPS。这是一个很好的方法来衡量任何动画呈如今你的iOS应用程序的性能/速度。
FPS在这个应用程序中被大大下降了,它显示的内容很重,就像图像中的阴影同样。在这种状况下,而不是直接将图像分配给UIImageView
的图像属性,尝试使用CoreGraphicsAPI在上下文中分别绘制图像。当在单独的线程中而不是在主线程中执行图像解压缩逻辑时,这会过分地减小图像显示时间。
Rasteralization是一个用于缓存复杂层信息的过程,以便这些视图在呈现时不会被从新绘制。重绘视图是FPS减小的主要缘由,所以,最好对将要重复使用的视图应用栅格化。
最后,我还总结了用于iOS动画的有用资源列表。当你在iOS动画上工做时,你可能会发现这很方便。此外,您可能还会发现这套设计工具在深刻研究动画以前,做为一个(设计)步骤颇有帮助。
我但愿我已经可以涵盖尽量多的主题,围绕iOS动画。若是我在这篇文章中遗漏了什么,请在下面的评论部分告诉我,我很乐意作这个补充!