《iOS动画》读书笔记·前序
《iOS动画》读书笔记·显示层动画
《iOS动画》读书笔记·内容层动画
《iOS动画》读书笔记·转场动画
UIView和CALayer的区别:
(1)UIView继承UIResponder
,因此UIView可以处理响应事件,而CALayer继承NSObject
,所以它只负责内容的创建、绘制。
(2)UIView负责对内容的管理,而CALayer负责对内容的绘制
(3)UIView中的位置属性只有frame,bounds,center
,而CALayer除了这些之外还有anchorPoint,position
(4)通过修改CALayer可以实现UIView无法实现的很多高级功能
Core Animation核心动画
Core Animation
为iOS核心动画,它提供了一组丰富的API可以用于制作各种高级炫酷的动画效果。CoreAnimation
来自iOS的QuartzCore.framework
框架,它具备以下特点:
(1)直接作用于CALayer图层上
(2)Core Animation的执行过程在后台执行,不阻塞主线程
(3)可用CALayer绝大多数属性绘制高级动画效果
Core Animation
下各种常用动画类的继承关系图
-
@protocol CAMediaTiming
有很多动画公共的属性,比如常见的duration / speed / repeatCount
等 -
CAAnimation
主要用于实现动画的委托代理方法,比如动画的开始事件和结束事件 -
CAPropertyAnimation
为动画属性,分为CABasicAnimation
基础动画和CAKeyframeAnimation
关键帧动画 -
CAAnimationGroup
组合动画
-CATransition
转场动画
CABasicAnimation基础动画合集
(1)位置动画
posion
注意animation.toValue属性表明改变了控件的位置,所以给一个新的position的x,y坐标 animation.byValue表明在控件原来位置的基础上,沿x,y坐标分别移动了多少
(2)缩放动画
transform.scale.x / transform.scale.y
,scale有x,y
两个属性表明当前UI控件的width/height的缩放系数
(3)旋转动画
transform.rotation
(4)位移动画
transform.translation.x / transform.translation.y
表示在x/y
方向上移动
(5)边框动画
animation.keyPath = "borderWidth"
(6)颜色渐变
animation.keyPath = "backgroundColor"
animation.keyPath = "borderColor"
(7)淡入淡出
animation.keyPath = "opacity"
(8)阴影渐变
animation.keyPath = "shadowOffset"
这里就不举具体的例子了,可以参考这篇→_→核心动画-Core Animation
Core Animation:
关键字 CAKeyframeAnimation
CAKeyframeAnimation
:是CALayer
层下的关键帧动画类,实现类似UIView的关键帧动画效果(前面有介绍)。ACKeyframeAnimation
是CAPropertyAnimation
的一个子类,与CABasicAnimation
原理类似,都是通过修改当前CALayer
图层的value
属性实现动画效果。不同的是CABasicAnimation
一般只使用fromeValue/toValue/byValue
,即只能修改一个value
值。而CAKeyframeAnimation
则可以修改一组value
值来实现对动画的更精确细腻的控制。
CAAnimation Group
:组合动画,把各种动画组合起来形成各种效果
CAKeyframeAnimation
动画属性要点:
(1)values
数组类型,数组中的每个元素描述了一个关键帧的相关属性。比如描述关键帧位置的动画时,values描述的是位置信息;比如描述关键帧缩放动画时,values描述的是缩放比例信息
(2)keyTimes
关键帧在动画周期默认是匀速的。如果设置了该属性,那么每个关键帧显示的周期为keyTimes*duration
(3)path
控制动画路径,通过设置CGPathRef/CGMutablePathRef
可以让动画按照自己绘制的路径运行
案例
具体示例代码看这里→_→https://github.com/SPIREJ/AnimationLayerSwift
1、CAEmitterCell粒子火焰效果
关键字:CAEmitterLayer / ACEmitterCell
粒子系统由两部分组成:
CAEmitterLayer
CAEmitterCell
(1)CAEmitterLayer
为粒子发射图层。该图层主要用于控制粒子展现范围、粒子发射位置、粒子发射形状、渲染模式等。通过CAEmitterCell构建的发射单元都受到CAEmitterLayer图层节制。
(2)CAEmitterCell
粒子发射单元,控制粒子的移动速度、方向、范围等等,这些属性可以制作酷炫的粒子特效动画
class EmitterFireVC: UIViewController {
let emitterCell = CAEmitterCell() //粒子单元cell
let emitterLayer = CAEmitterLayer()//粒子发射图层
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.black;
// Do any additional setup after loading the view.
self.navigationItem.title = "粒子火焰效果"
emitterCell.name = "fire"//粒子单元名称
emitterCell.emissionLongitude = CGFloat(Double.pi)//该d粒子系统在xy平面的发射角度
emitterCell.velocity = -1//粒子速度1,负表示沿y反方向运动
emitterCell.velocityRange = 50//粒子速度范围
emitterCell.emissionRange = 1.1//粒子发射角度
emitterCell.yAcceleration = -200//粒子y方向的加速度分量
emitterCell.scaleSpeed = 0.3//缩放比例,超大火苗
emitterCell.birthRate = 500//粒子数
emitterCell.lifetime = 1//粒子生命周期
// 火焰颜色
emitterCell.color = UIColor(red: 0.8, green: 0.4, blue: 0.2, alpha: 0.1).cgColor
// 必须要设置粒子的“种子”内容
emitterCell.contents = UIImage(named: "fire.png")!.cgImage
emitterLayer.position = self.view.center//粒子发射位置
emitterLayer.emitterSize = CGSize(width: 50, height: 10)//当前火苗大小
// 当前粒子渲染模式 和 发射源模式
emitterLayer.renderMode = .additive
emitterLayer.emitterMode = .outline
emitterLayer.emitterShape = .line
// 粒子单元部署到粒子发射图层中
emitterLayer.emitterCells = [emitterCell]
self.view.layer.addSublayer(emitterLayer)
}
// 粒子速度
@IBAction func velocityChanged(_ sender: UISlider) {
// 重置粒子速度
emitterLayer.setValue(sender.value, forKeyPath: "emitterCells.fire.velocity")
}
// 粒子数
@IBAction func birthRateChanged(_ sender: UISlider) {
// 重置粒子生成速度,即粒子数
emitterLayer.setValue(sender.value, forKeyPath: "emitterCells.fire.birthRate")
}
}
2、CAEmitterCell粒子霓虹效果
关键字:CAEmitterLayer / ACEmitterCell
class EmitterNenoVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.navigationItem.title = "霓虹效果"
self.view.backgroundColor = UIColor.black
let emitterCell = CAEmitterCell()
emitterCell.name = "neonlight"
emitterCell.emissionLongitude = CGFloat(Double.pi*2)// emissionLongitude:x-y 平面的 发 射方向
emitterCell.velocity = 50// 粒子速度
emitterCell.velocityRange = 50// 粒子速度范围
emitterCell.scaleSpeed = -0.2// 缩放比例 超大火苗
emitterCell.scale = 0.1//缩放比例
//R G B alpha的颜色速度渐变效果
emitterCell.redSpeed = -0.2
emitterCell.greenSpeed = -0.1
emitterCell.blueSpeed = 0.1
emitterCell.alphaSpeed = -0.2
emitterCell.birthRate = 100//粒子生成速度
emitterCell.lifetime = 4//粒子生命周期
emitterCell.color = UIColor.white.cgColor//粒子背景颜色
//粒子效果内容
emitterCell.contents = UIImage(named: "neonlight.png")!.cgImage
let emitterLayer = CAEmitterLayer()
emitterLayer.position = self.view.center// 粒子发射位置
emitterLayer.emitterSize = CGSize(width: 2, height: 2)// 控制粒子大小
emitterLayer.renderMode = CAEmitterLayerRenderMode.backToFront//着色(渲染)模式
emitterLayer.emitterMode = CAEmitterLayerEmitterMode.outline// 控制发射源模式 即形状
emitterLayer.emitterShape = CAEmitterLayerEmitterShape.circle//形状
emitterLayer.emitterCells = [emitterCell]
self.view.layer.addSublayer(emitterLayer)
}
}
3、CAGradientLayer 颜色梯度/位置梯度
CAGradientLayer
可以拆解为三个主要组成部分
CA
:CoreAnimation的缩写,表明使用的是iOS框架下的核心动画部分
Gradient
:梯度的意思,描述当前动画的特点,实现一些梯度功能的动画效果。比如位置的梯度变化、颜色的梯度渐变等
Layer
:当前动画作用在Layer内容层
- CALayer坐标系
属性
- colors
var colors: [AnyObject]?
一个内部是CGColorRef
的数组,规定所有的梯度所显示的颜色,默认为nil
- locations
var locations: [NSNumber]?
一个内部是NSNumber
的可选数组,规定所有的颜色梯度的区间范围,选值只能在0到1之间
,并且数组的数据必须单增,默认值为nil
- endPoint
var endPoint: CGPoint
图层颜色绘制的终点坐标,也就是阶梯图层绘制的结束点,默认值是(0.5,1.0)
- startPoint
var startPoint: CGPoint
与endPoint
相互对应,就是绘制阶梯图层的起点坐标,绘制颜色的起点,默认值是(0.5,0.0)
- type
var type:String
绘制类型,默认值是kCAGradientLayerAxial
,也就是线性绘制,各个颜色阶层直接的变化是线性的
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.view.backgroundColor = UIColor.black
let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 200))
view.center = self.view.center
self.view.addSubview(view)
let gradientLayer:CAGradientLayer = CAGradientLayer()
gradientLayer.frame = view.bounds
gradientLayer.startPoint = CGPoint(x: 0, y: 0)
gradientLayer.endPoint = CGPoint(x: 0, y: 1)
gradientLayer.colors = [UIColor.clear.cgColor,UIColor.white.cgColor,UIColor.clear.cgColor]
gradientLayer.locations = [0.0, 0.5, 1.0]
view.layer.addSublayer(gradientLayer)
let gradientAnimation:CABasicAnimation = CABasicAnimation()
gradientAnimation.keyPath = "colors"
gradientAnimation.fromValue = [UIColor.clear.cgColor,UIColor.white.cgColor,UIColor.clear.cgColor]
gradientAnimation.toValue = [UIColor.blue.cgColor,UIColor.red.cgColor,UIColor.cyan.cgColor]
//另一种方式 位置
//gradientLayer.locations = [0.0, 0.05, 0.1]
//gradientAnimation.keyPath = "locations"
//gradientAnimation.fromValue = [0.0, 0.05, 0.1]
//gradientAnimation.toValue = [0.9, 0.95, 1.0]
gradientAnimation.duration = 3.0
// 动画结束后保持结束后的状态
gradientAnimation.isRemovedOnCompletion = false
gradientAnimation.fillMode = .forwards
gradientLayer.add(gradientAnimation, forKey: nil)
CAGradientLayer
结合CoreAnimation
可以实现很多酷炫的效果,有兴趣的朋友可以自行研究
4、CAReplicatorLayer图层复制
#关键字 CAReplicatorLayer
主要用于图层的快速复制,并且复制会保持被复制图层的各种基础属性及动画
基本属性
instanceCount
var instanceCount: Int
拷贝图层的次数,包括其所有的子图层,默认值是1,也就是没有任何子图层被复制instanceDelay
var instanceDelay: CFTimeInterval
在短时间内的复制延时,一般用在动画上(支持动画的延时)instanceTransform
var instanceTransform: CATransform3D
复制图层在被创建时产生的和上一个复制图层的位移(位移的锚点是CAReplicatorlayer的中心点)preservesDepth
var preservesDepth: Bool
如果设置为YES,图层将保持于CATransformLayer类似的性质和相同的限制instanceColor
var instanceColor: CGColor?
设置多个复制图层的颜色,默认位白色instanceRedOffset
var instanceRedOffset: Float
设置每个复制图层相对上一个复制图层的红色偏移量instanceGreenOffset
var instanceGreenOffset: Float
设置每个复制图层相对上一个复制图层的绿色偏移量instanceBlueOffset
var instanceBlueOffset: Float
设置每个复制图层相对上一个复制图层的蓝色偏移量instanceAlphaOffset
var instanceAlphaOffset: Float
设置每个复制图层相对上一个复制图层的透明度偏移量
(1) 图层复制 - 雷达效果
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.view.backgroundColor = UIColor.white
// 背景视图
let bgView = UIView(frame: CGRect(x: 0, y: 0, width: kWidth, height: 200))
bgView.center = self.view.center
bgView.backgroundColor = UIColor.lightGray
self.view.addSubview(bgView)
// 动画原图层,就是不断变大的那个圆
let animationLayer = CAShapeLayer()
animationLayer.backgroundColor = UIColor.red.cgColor
animationLayer.bounds = CGRect(x: 0, y: 0, width: 20, height: 20)
animationLayer.cornerRadius = 10
animationLayer.position = CGPoint(x: kWidth/2.0, y: 100)
// 动画 - 放大
let transformScaleAnim = CABasicAnimation(keyPath: "transform")
let value = NSValue.init(caTransform3D:CATransform3DMakeScale(10, 10, 1))
transformScaleAnim.toValue = value
// 动画 - 透明度
let alphaAnim = CABasicAnimation(keyPath: "opacity")
alphaAnim.toValue = 0
// 加入到动画组
let animGroup = CAAnimationGroup()
animGroup.animations = [transformScaleAnim, alphaAnim]
animGroup.duration = 2
animGroup.repeatCount = HUGE
animationLayer.add(animGroup, forKey: nil)
// 复制图层
let replicatorLayer = CAReplicatorLayer()
replicatorLayer.addSublayer(animationLayer)
replicatorLayer.instanceCount = 3 //复制图层数
replicatorLayer.instanceDelay = 0.3//复制间隔时间
// 加载到视图中显示
bgView.layer.addSublayer(replicatorLayer)
}
(2) 图层复制 - 加载动画效果
func ui_circle() {
// 背景视图
let bgView = UIView(frame: CGRect(x: 0, y: 0, width: kWidth, height: 200))
bgView.center = self.view.center
bgView.backgroundColor = UIColor.lightGray
self.view.addSubview(bgView)
// 动画原图层,就是不断转圈的圆
let animationLayer = CAShapeLayer()
animationLayer.backgroundColor = UIColor.red.cgColor
animationLayer.bounds = CGRect(x: 0, y: 0, width: 20, height: 20)
animationLayer.cornerRadius = 10
animationLayer.position = CGPoint(x: kWidth/2.0, y: 50)
animationLayer.transform = CATransform3DMakeScale(0, 0, 0)//初始隐藏
// 动画 - 缩放
let transformAnim = CABasicAnimation(keyPath: "transform")
transformAnim.duration = 2
transformAnim.repeatCount = HUGE
transformAnim.fromValue = NSValue.init(caTransform3D: CATransform3DMakeScale(1, 1, 1))
transformAnim.toValue = NSValue.init(caTransform3D: CATransform3DMakeScale(0.1, 0.1, 0.1))
animationLayer.add(transformAnim, forKey: nil)
// 复制图层
let replicatorLayer = CAReplicatorLayer()
replicatorLayer.frame = bgView.bounds
replicatorLayer.addSublayer(animationLayer)
replicatorLayer.instanceCount = 10 //复制图层数
replicatorLayer.instanceDelay = 0.2//复制间隔时间
replicatorLayer.instanceTransform = CATransform3DMakeRotation(CGFloat(Double.pi*2/Double(10)), 0, 0, 1.0)
// 加载到视图中显示
bgView.layer.addSublayer(replicatorLayer)
}
完整示例代码https://github.com/SPIREJ/AnimationLayerSwift
如果您有兴趣的话
上一节《iOS动画》读书笔记·显示层动画
下一节《iOS动画》读书笔记·转场动画