Swift学习29:动画

张建 lol

iOS 动画框架

  • 从图中可以看出,iOS 从上层到底层你会接触到 UIKit、Core Animation、Core Graphics。使用难度依次递增,实现效果的复杂度越来越高

CALager 绘制的子类

  • CAShapeLayer:用于绘制曲线等图形
  • CATextLayer:用于绘制文字
  • CAGradientLayer:用于绘制渐变

UIView和CALayer关系

  • UIView 可以 响应事件;CALayer 不可以
  • UIView 主要是对 显示内容的管理;CALayer 主要侧重 显示内容的绘制
  • UIView 是 iOS 平台对 CALayer封装;CALayer 是 iOS 和 OSX 跨平台的类
  • UIView 的很多属性其实是返回 CALayer 的属性,比如 frame、center 等等

导入头文件

1
import ImageIO

UIView的Block动画

  1. UIViewBlock 动画的适用范围

UIView 的动画可以修改一些 属性,将其以动画的形式展示出来。可修改的属性如下:frame(尺寸)\bound(大小)\center(中心)\ transform(旋转)\alpha(透明度)\ backgroundColor(背景颜色)\ contentStretch(内容拉伸) 等。

  1. 使用 UIView 实现普通动画
  • 只可以设置动画内容的动画函数
1
2
3
4
5
6
7
8
/*!
1、设置动画时间
2、设置动画内容
*/
UIView.animate(withDuration:5) {
// 位置和颜色的变换
animationView.frame = CGRect.init(x: self.view.frame.width - 200, y: 50, width:100, height: 200)
}
  • 可设置动画时间、动画内容、动画结束后的内容的函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 /*!
1、设置动画时间
2、设置动画内容
3、设置动画结束后的处理事件
*/
UIView.animate(withDuration: 5, animations: {
// 位置和颜色的变换
animationView.frame = CGRect.init(x: 100, y: 50, width: 100, height: 200)
}) { (isFinish) in
if isFinish {
// 变色
self.View1!.backgroundColor = UIColor.magenta
}
}
  • 设置动画时间、动画延迟时间、动画内容、动画结束内容的动画函数
1
2
3
4
5
6
7
8
9
10
11
12
/*!
可设置延时时间的动画

@withDuration : 设置动画时间
@delay : 设置动画延迟时间
@options : 设置动画的形式
*/
UIView.animate(withDuration: 5, delay: 2, options: .allowUserInteraction, animations: {
// code.... 动画的内容
}) { (isFinish) in
// code.... 动画结束后的处理内容
}
  • 弹簧动画函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*!
弹簧式动画

@withDuration : 设置动画时间
@delay : 设置动画延时时间
@usingSpringWithDamping : 设置阻尼系数(该数字越大,动画弹动的次数越少)
@initialSpringVelocity : 设置初始速度(该数字越大,震动的振幅越大)
@options : 设置动画的出现形式
*/
UIView.animate(withDuration: 5, delay: 2, usingSpringWithDamping: 0.1, initialSpringVelocity: 10, options: .curveEaseIn, animations: {
// code.... 动画的内容
animationView.frame = CGRect.init(x: (self.View1?.center.x)!-20, y: 110, width: 40, height: 40)
}) { (isFinish) in
// code.... 动画结束后的处理内容
animationView.frame = CGRect.init(x: self.View1!.center.x-40, y: 110, width: 80, height: 80)
}
  • 帧动画函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/*!
帧动画

@withDuration : 设置动画时间
@delay : 设置动画延迟时间
@options :设置动画形式
*/
UIView.animateKeyframes(withDuration: 8, delay: 0, options: .calculationModeLinear, animations: {
// code.... 动画的内容
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 1.0/4, animations: {
animationView.backgroundColor = UIColor.red
})
UIView.addKeyframe(withRelativeStartTime: 1.0/4, relativeDuration: 1.0/4, animations: {
animationView.backgroundColor = UIColor.green
})
UIView.addKeyframe(withRelativeStartTime: 2.0/4, relativeDuration: 1.0/4, animations: {
animationView.backgroundColor = UIColor.blue
})
UIView.addKeyframe(withRelativeStartTime: 3.0/4, relativeDuration: 1.0/4, animations: {
animationView.backgroundColor = UIColor.magenta
})
UIView.addKeyframe(withRelativeStartTime: 4.0/4, relativeDuration: 1.0/4, animations: {
animationView.backgroundColor = UIColor.purple
})
}) { (isFinish) in
// code.... 动画结束后的处理内容
animationView.backgroundColor = UIColor.cyan
}
  • 关键帧动画的单帧动画设置
1
2
3
4
5
6
7
8
9
/*!
帧动画

@withRelativeStartTime : 设置动画的开始时间
@relativeDuration : 动画的持续时间
*/
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 1.0/4, animations: {
animationView.backgroundColor = UIColor.purple
})
  1. UIView 转场动画
  • 单个 View 转场动画
1
2
3
4
5
6
7
8
9
10
11
12
/*!
单个View的转场动画

@with : 要转场的View
@duration : 转场时间
@options : 动画的类型
*/
UIView.transition(with: animationView, duration: 5, options:.transitionCurlUp, animations: {
self.imageView4?.image = UIImage.init(named: "2.jpg")
}) { (isFinsish) in
// code .... 转场结束事件处理
}
  • 两个 View 的转场动画
1
2
3
4
5
6
7
8
9
10
11
/*!
转场动画

@from : 起始View
@to : 结束View
@duration : 动画时间
@options : 动画的形式
*/
UIView.transition(from: fromView, to: toView, duration: 5, options: [ .transitionFlipFromLeft,.showHideTransitionViews]) { (isFinish) in
// code .... 两个View的其他处理内容
}
  1. UIView 基本动画写法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// TODO: 动画的一般写法
func basicAnimation() -> Void {
// 开始某个动画
UIView.beginAnimations("animation", context: nil)
// 设置动画时间
UIView.setAnimationDuration(5)
// 设置动画的延时时间
UIView.setAnimationDelay(0.25)
// 设置动画的效果
UIView.setAnimationCurve(.easeInOut)
// 设置动画是否重复,0为无限重复
UIView.setAnimationRepeatCount(0)
// 设置动画的代理
UIView.setAnimationDelegate(self)
// 设置动画将要触发的时调用的方法
UIView.setAnimationWillStart(#selector(willStartMethod))
// 设置动画结束时触发的方法
UIView.setAnimationDidStop(#selector(didStopMethod))
// 设置动画是否可用
UIView.setAnimationsEnabled(true)
// 设置动画是否从当前状态开始(例如:一个动画正在播放时,我们要进行下一个动画,如果设置为 true 时,动画将从当前动画状态开始动画。为 false时是等上一个动画停止时,开始下一个动画)
UIView.setAnimationBeginsFromCurrentState(true)
// 设置动画开始的时间
UIView.setAnimationStart(Date.init())
// 设置动画是否执行动画回路,前提 UIView.setAnimationRepeatCount(0) 为 0
UIView.setAnimationRepeatAutoreverses(true)
// 设置单个View的转场动画
UIView.setAnimationTransition(.flipFromLeft, for: self.view, cache: true)
// 设置动画的结束
UIView.commitAnimations()
}

// 动画代理触发事件

@objc func willStartMethod() {
// 动画将要开始执行触发的代理事件
}

@objc func didStopMethod() {
// 动画结束后触发的方法
}

Core Animation 动画

  1. Core Animation 动画的适用场景?
  • 当我们无法用 Block 动画解决动画问题时,就是 Core Animation 出场了
  • 比如:改变 cornerRadius,沿着一条曲线移动 view 等等
  1. Core Animation 的所有功能都是基于 layer 对吗?
  • 对,都基于 layer
  • 当你通过 Core Animation 修改了 layer 的属性时,Core Animation 会通过
    GPU 来重新渲染位图,因为是硬件渲染,因此速度非常快。
  1. 几种常用的 CALayer 子类
  • CAEmitterLayer

CAEmitterLayer 是一个粒子发射器系统,负责粒子的创建和发射源属性的配置。它可以创建出炫酷的粒子效果动画

  • CAGradientLayer

可以创建色彩渐变的图层效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 创建图层对象
let gradientLayer = CAGradientLayer()
// 设置图层尺寸与位置
gradientLayer.bounds = CGRect(x: 0, y: 100, width: 100, height: 100)
gradientLayer.position = CGPoint(x: 100, y: 100)
// 设置要进行色彩渐变的颜色
gradientLayer.colors = [UIColor.red.cgColor,UIColor.green.cgColor,UIColor.blue.cgColor]
// 设置要进行渐变的临界位置 当红色渲染到1/5后开始向绿色进行渐变,绿色渲染到1/2后开始向蓝色进行渐变,当到达7/10距离后完成渐变过程,开始渲染为纯蓝色
gradientLayer.locations = [NSNumber(value: 0.2),NSNumber(value: 0.5),NSNumber(value: 0.7)]
// 设置渐变的起始点与结束点 (0,0)左上角 (1,1)右下角
gradientLayer.startPoint = CGPoint(x: 0, y: 0.5)
gradientLayer.endPoint = CGPoint(x: 1, y: 0.5)
// 添加视图
self.view.layer.addSublayer(gradientLayer)
  • CAEAGLLayer 类

可以通过 OpenGL ES 来进行界面的绘制

  • CAReplicatorLayer 类

CAReplicatorLayer 是一个图层容器,会对其中的子图层进行复制和属性偏移。可以用来创建类型倒影效果,也可以进行图层的变换复制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 创建拷贝图层
let replicatorLayer = CAReplicatorLayer()
replicatorLayer.position = CGPoint.zero
// 创建内容图层
let subLayer = CALayer()
subLayer.bounds = CGRect(x: 0, y: 0, width: 20, height: 20)
subLayer.position = CGPoint(x: 30, y: 100)
subLayer.backgroundColor = UIColor.red.cgColor
replicatorLayer.addSublayer(subLayer)
// 设置每次拷贝将副本沿x轴平移30个单位
replicatorLayer.instanceTransform = CATransform3DMakeTranslation(30, 0, 0)
// 设置拷贝副本的个数
replicatorLayer.instanceCount = 10
// 添加视图
self.view.layer.addSublayer(replicatorLayer)
  • CAScrollLayer类

可以让其管理的多个子层进行滑动,但是只能通过代码进行管理,不能进行用户点按触发

  • CAShapeLayer类

可以在图层上直接绘制出自定义的形状

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 创建图层
let shapeLayer = CAShapeLayer()
shapeLayer.position = CGPoint.zero
// 创建图形路径
let path = CGMutablePath()
// 设置路径起点
path.move(to: CGPoint(x: 100, y: 100))
// 进行画线
path.addLine(to: CGPoint(x: 300, y: 100))
path.addLine(to: CGPoint(x: 200, y: 200))
path.addLine(to: CGPoint(x: 100, y: 100))
// 设置图层路径
shapeLayer.path = path
// 设置图形边缘线条起点
shapeLayer.strokeStart = 0
// 设置图形边缘线条终点
shapeLayer.strokeEnd = 1
// 设置填充规则
shapeLayer.fillRule = CAShapeLayerFillRule.evenOdd
// 设置填充颜色
shapeLayer.fillColor = UIColor.red.cgColor
// 设置边缘线条颜色
shapeLayer.strokeColor = UIColor.blue.cgColor
// 设置边缘线条宽度
shapeLayer.lineWidth = 1
self.view.layer.addSublayer(shapeLayer)
  • CATextLayer类

用于进行文字的绘制

  • CATiledLayer类

瓦片视图,可以分区域绘制,常用于在一张大的图片中分区域绘制

  • CATransformLayer类

用于构建一些图层变化效果,包括3D效果的图层变换

  1. CoreAnimation 框架中的属性动画

CAAnimation 类是 CoreAnimation 子类,主要分为:CAPropertyAnimation(CABasicAnimation 属性过渡动画、CAKeyframeAnimation 关键帧属性过渡动画)、CATransitionCAAnimationGroup

  • CABasicAnimation 属性过渡动画
1
2
3
4
5
6
7
8
9
10
// 创建动画实例,keyPath为要进行属性动画的属性路径 transform.rotation.z 表示图形属性中以 z 轴为中心轴的旋转属性
let basicAni = CABasicAnimation(keyPath: "transform.rotation.z")
// 从0度开始旋转
basicAni.fromValue = NSNumber(value: 0)
// 旋转到180度
basicAni.toValue = NSNumber(value: Double.pi)
// 设置动画播放的时长
basicAni.duration = 2
// 将动画作用于当前界面的视图Layer层上
self.view.layer.add(basicAni, forKey: nil)
  • CAKeyframeAnimation关键帧动画
1
2
3
4
5
6
7
8
// 创建动画实例,keyPath为要进行属性动画的属性路径 transform.rotation.z 表示图形属性中以z轴为中心轴的旋转属性
let keyframeAni = CAKeyframeAnimation(keyPath: "transform.rotation.z")
// 从0度开始旋转
keyframeAni.values = [NSNumber(value: 0),NSNumber(value: Double.pi/4),NSNumber(value: 0),NSNumber(value: Double.pi)]
// 设置动画播放的时长
keyframeAni.duration = 3
// 将动画作用于当前界面的视图Layer层上
self.view.layer.add(keyframeAni, forKey: "")
  • CASpringAnimation类似弹簧的阻尼动画
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 创建动画实例
let springAni = CASpringAnimation(keyPath: "position.y")
// 模拟重物质量,必须大于0,默认为1,会影响惯性
springAni.mass = 2
// 模拟弹簧劲度系数,必须大于0,这个值越大,则回弹越快
springAni.stiffness = 5
// 设置阻尼系数,必须大于0,这个值越大,回弹的幅度越小
springAni.damping = 2
springAni.toValue = 300
springAni.duration = 3
// 创建演示动画的Layer
let layer = CALayer()
layer.position = CGPoint(x: 100, y: 100)
layer.bounds = CGRect(x: 0, y: 0, width: 100, height: 100)
layer.backgroundColor = UIColor.red.cgColor
self.view.layer.addSublayer(layer)
layer.add(springAni, forKey: "")
  • CATransition 实现转场动画
1
2
3
4
5
6
7
8
9
10
11
12
// 创建转场动画实例
let transAni = CATransition()
// 设置转场动画类型
transAni.type = CATransitionType.reveal
// 设置转场动画方向
transAni.subtype = CATransitionSubtype.fromTop
let layer = CALayer()
layer.position = CGPoint(x: 100, y: 100)
layer.bounds = CGRect(x: 0, y: 0, width: 100, height: 100)
layer.backgroundColor = UIColor.red.cgColor
layer.add(transAni, forKey: "")
self.view.layer.addSublayer(layer)

type转场动画属性

1
2
3
4
5
6
7
8
// 渐入效果
transAni.type = CATransitionType.fade
// 移入效果
transAni.type = CATransitionType.moveIn
// 压入效果
transAni.type = CATransitionType.push
// 溶解效果
transAni.type = CATransitionType.reveal

subtype属性

1
2
3
4
5
6
7
8
// 从右侧执行
transAni.subtype = CATransitionSubtype.fromRight
// 从左侧执行
transAni.subtype = CATransitionSubtype.fromLeft
// 从上侧执行
transAni.subtype = CATransitionSubtype.fromTop
// 从下侧执行
transAni.subtype = CATransitionSubtype.fromBottom
  • CAAnimationGroup组合动画
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 创建背景色过渡动画
let basicAni = CABasicAnimation(keyPath: "backgroundColor")
basicAni.toValue = UIColor.green.cgColor
// 创建形变动画
let basicAni2 = CABasicAnimation(keyPath: "transform.scale.x")
basicAni2.toValue = NSNumber(value: 2)
// 进行动画组合
let groupAni = CAAnimationGroup()
groupAni.animations = [basicAni,basicAni2]
groupAni.duration = 3

let layer = CALayer()
layer.position = CGPoint(x: 100, y: 100)
layer.bounds = CGRect(x: 0, y: 0, width: 100, height: 100)
layer.backgroundColor = UIColor.red.cgColor
layer.add(groupAni, forKey: "")
self.view.layer.addSublayer(layer)
  • Post title:Swift学习29:动画
  • Post author:张建
  • Create time:2023-04-03 13:43:21
  • Post link:https://redefine.ohevan.com/2023/04/03/Swift/Swift学习29:动画/
  • Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.