YTAnimation
iOS动画集锦, swift, 核心动画, 基础动画,关键帧动画, 组动画, 过渡动画, 进度条,项目案例.
Install / Use
/learn @YTiOSer/YTAnimationREADME
YTAnimation
iOS 动画主要是指
Core Animation框架,Core Animation是iOS和OS X平台上负责图形渲染与动画的基础框架。Core Animation可以作用于动画视图或者其他可视元素,可以完成动画所需的大部分绘帧工作。Core Animation系统已经进行了封装, 所以在使用的时候你只需要配置少量的动画参数(如开始点的位置和结束点的位置)即可使用Core Animation的多种动画效果。Core Animation将大部分实际的绘图任务交给了图形硬件(GPU)来处理,图形硬件会加速图形渲染的速度。这种自动化的图形加速技术让动画拥有更高的帧率并且显示效果更加平滑,不会加重CPU的负担而影响程序的运行速度。
本文主要总结下平时常用的动画, 如: 基础动画(CABasicAnimation)、关键帧动画(CAKeyframeAnimation)、组动画(CAAnimationGroup)、过渡动画(CATransition), 最后也扩展了下, 做了进度条、贝塞尔曲线画心❤️、弹球、钉钉效果、点赞等动画,希望对大家有所帮助.

一、Core Animation类简介
-
首先通过官方的
Core Animation类图了解下各个类之间的关系. 官网链接:Core Animation
建议详细看下上图, 这里对 CAAnimation的子类和相互关系及属性介绍的比较详细, 看完后会对各个动画类型有个大概的了解. -
接下来详细介绍下动画的各个属性及作用
- fromValue: 动画的开始值(Any类型, 根据动画不同可以是
CGPoint、NSNumber等) - toValue: 动画的结束值, 和fromValue类似
- beginTime: 动画的开始时间
- duration : 动画的持续时间
- repeatCount : 动画的重复次数
- fillMode: 动画的运行场景
- isRemovedOnCompletion: 完成后是否删除动画
- autoreverses: 执行的动画按照原动画返回执行
- path:关键帧动画中的执行路径
- values: 关键帧动画中的关键点数组
- animations: 组动画中的动画数组
- delegate : 动画代理, 封装了动画的执行和结束方法
- timingFunction: 控制动画的显示节奏, 系统提供五种值选择,分别是:
1.
kCAMediaTimingFunctionDefault( 默认,中间快) 2.kCAMediaTimingFunctionLinear(线性动画) 3.kCAMediaTimingFunctionEaseIn(先慢后快 慢进快出) 4.kCAMediaTimingFunctionEaseOut(先块后慢快进慢出) 5.kCAMediaTimingFunctionEaseInEaseOut(先慢后快再慢) - type: 过渡动画的动画类型,系统提供了多种过渡动画, 分别是:
1:
fade(淡出 默认) 2:moveIn(覆盖原图) 3:push(推出) 4:fade(淡出 默认) 5:reveal(底部显示出来) 6:cube(立方旋转) 7:suck(吸走) 8:oglFlip(水平翻转 沿y轴) 9:ripple(滴水效果) 10:curl(卷曲翻页 向上翻页) 11:unCurl(卷曲翻页返回 向下翻页) 12:caOpen(相机开启) 13:caClose(相机关闭) - subtype : 过渡动画的动画方向, 系统提供了四种,分别是:
1.
fromLeft( 从左侧) 2.fromRight(从右侧) 3.fromTop(有上面) 4.fromBottom(从下面)
二、Core Animation的使用
1. 基础动画( CABasicAnimation )
基础动画主要提供了对于CALayer对象中的可变属性进行简单动画的操作。比如:位移、旋转、缩放、透明度、背景色等。 基础动画根据
keyPath来区分不同的动画,, 系统提供了多个类型,如:transform.scale(比例转换)、transform.scale.x、transform.scale.y、transform.rotation(旋转) 、transform.rotation.x(绕x轴旋转)、transform.rotation.y(绕y轴旋转)、transform.rotation.z(绕z轴旋转)、opacity(透明度)、margin、backgroundColor(背景色)、cornerRadius(圆角)、borderWidth(边框宽)、bounds、contents、contentsRect、cornerRadius、frame、hidden、mask、masksToBounds、shadowColor(阴影色)、shadowOffset、shadowOpacity、shadowOpacity, 在使用时候, 需要根据具体的需求选择合适的.
效果图如下:

- 位移动画
func positionAnimation() {
let animation = CABasicAnimation.init(keyPath: "position") //keyPath为系统提供
animation.fromValue = CGPoint.init(x: margin_ViewMidPosition, y: kScreenH / 2 - margin_Top)
animation.toValue = CGPoint.init(x: kScreenW - margin_ViewMidPosition, y: kScreenH / 2 - margin_Top)
animation.duration = 1.0
view_Body.layer.add(animation, forKey: "positionAnimation") //key自定义
}
- 旋转动画:
func rotateAnimation() {
let animation = CABasicAnimation.init(keyPath: "transform.rotation.z")
animation.toValue = NSNumber.init(value: Double.pi)
animation.duration = 0.1
animation.repeatCount = 1e100 //无限大重复次数
view_Body.layer.add(animation, forKey: "rotateAnimation")
}
- 缩放动画
func scaleAnimation() {
let animation = CABasicAnimation.init(keyPath: "transform.scale")
animation.toValue = NSNumber.init(value: 2.0)
animation.duration = 1.0
view_Body.layer.add(animation, forKey: "scaleAnimation")
}
- 透明度动画
func opacityAnimation() {
let animation = CABasicAnimation.init(keyPath: "opacity")
animation.fromValue = NSNumber.init(value: 1.0)
animation.toValue = NSNumber.init(value: 0.0)
animation.duration = 1.0
view_Body.layer.add(animation, forKey: "opacityAnimation")
}
- 背景色动画
func backgroundColorAnimation() {
let animation = CABasicAnimation.init(keyPath: "backgroundColor")
animation.toValue = UIColor.green.cgColor //因为layer层动画, 所以需要使用cgColor
animation.duration = 1.0
view_Body.layer.add(animation, forKey: "backgroundColorAnimation")
}
2. 关键帧动画( CAKeyframeAnimation )
CAKeyframeAnimation和CABasicAnimation都属于CAPropertyAnimatin的子类。不同的是CABasicAnimation只能从一个数值(fromValue)变换成另一个数值(toValue),而CAKeyframeAnimation则会使用一个数组(values) 保存一组关键帧, 也可以给定一个路径(path)制作动画。
CAKeyframeAnimation主要有 三个 重要属性:
- values:存放关键帧(
keyframe)的数组,动画对象会在指定的时间(duration)内,依次显示values数组中的每一个关键帧 . - path:可以设置一个
CGPathRef或CGMutablePathRef,让层跟着路径移动.path只对CALayer的anchorPoint和position起作用, 如果设置了path,那么values将被忽略. - keyTimes:可以为对应的关键帧指定对应的时间点,其取值范围为0到1.0,
keyTimes中的每一个时间值都对应values中的每一帧.当keyTimes没有设置的时候,各个关键帧的时间是根据duration平分的。
以抖动截图为例, 效果图如下:

动画代码如下:
- 关键帧动画
func keyFrameAnimation() {
let animation = CAKeyframeAnimation.init(keyPath: "position")
let value_0 = CGPoint.init(x: margin_ViewMidPosition, y: kScreenH / 2 - margin_ViewWidthHeight)
let value_1 = CGPoint.init(x: kScreenW / 3, y: kScreenH / 2 - margin_ViewWidthHeight)
let value_2 = CGPoint.init(x: kScreenW / 3, y: kScreenH / 2 + margin_ViewMidPosition)
let value_3 = CGPoint.init(x: kScreenW * 2 / 3, y: kScreenH / 2 + margin_ViewMidPosition)
let value_4 = CGPoint.init(x: kScreenW * 2 / 3, y: kScreenH / 2 - margin_ViewWidthHeight)
let value_5 = CGPoint.init(x: kScreenW - margin_ViewMidPosition, y: kScreenH / 2 - margin_ViewWidthHeight)
animation.values = [value_0, value_1, value_2, value_3, value_4, value_5]
animation.duration = 2.0
view_Body.layer.add(animation, forKey: "keyFrameAnimation")
}
- 路径动画
func pathAnimation() {
let animation = CAKeyframeAnimation.init(keyPath: "position")
let path = UIBezierPath.init(arcCenter: CGPoint.init(x: kScreenW / 2, y: kScreenH / 2), radius: 60, startAngle: 0.0, endAngle: .pi * 2, clockwise: true)
animation.duration = 2.0
animation.path = path.cgPath
view_Body.layer.add(animation, forKey: "pathAnimation")
}
- 抖动动画
func shakeAnimation() {
let animation = CAKeyframeAnimation.init(keyPath: "transform.rotation")
let value_0 = NSNumber.init(value: -Double.pi / 180 * 8)
let value_1 = NSNumber.init(value: Double.pi / 180 * 8)
animation.values = [value_0, value_1, value_0]
animation.duration = 1.0
animation.repeatCount = 1e100
view_Body.layer.add(animation, forKey: "shakeAnimation")
}
3. 组动画( CAAnimationGroup )
CAAnimationGroup 是 CAAnimation 的子类,可以保存一组动画对象,可以保存基础动画、关键帧动画等,数组中所有动画对象可以同时并发运行, 也可以通过实践设置为串行连续动画.
效果截图如下:

动画代码如下:
- 同时
//同时
func sameTimeAnimation() {
let animation_Position = CAKeyframeAnimation.init(keyPath: "position")
let value_0 = CGPoint.init(x: margin_ViewMidPosition, y: kScreenH / 2 - margin_ViewMidPosition)
let value_1 = CGPoint.init(x: kScreenW / 3, y: kScreenH / 2 - margin_ViewMidPosition)
let value_2 = CGPoint.init(x: kScreenW / 3, y: kScreenH / 2 + margin_ViewMidPosition)
let value_3 = CGPoint.init(x: kScreenW / 3 * 2, y: kScreenH / 2 + margin_ViewMidPosition)
let value_4 = CGPoint.init(x: kScreenW / 3 * 2, y: kScreenH / 2 - margin_ViewMidPosition)
let value_5 = CGPoint.init(x: kScreenW - margin_ViewMidPosition, y: kScreenH / 2 - margin_ViewMidPosition)
animation_Position.values = [value_0, value_1, value_2, value_3, value_4, value_5]
let animation_BGColor = CABasicAnimation.init(keyPath: "backgroundColor")
animation_BGColor.toValue = UIColor.green.cgColor
let animation_Rotate = CABasicAnimation.init(keyPath: "transform.rotation")
animation_Rotate.toValue = NSNumber.init(value: Double.pi * 4)
let animation_Group = CAAnimationGroup()
animation_Group.animations = [animation_Position, animation_BGColor, animation_Rotate]
animation_Group.duration = 4.0
view_Body.layer.add(animation_Group, forKey: "groupAnimation")
}
- 连续
//连续动画 最主要的是处理好各个动画时间的衔接
func goOnAnimation() {
//定义一个动画开始的时间
let currentTime = CACurrentMediaTime()
let animation_Position = CABasicAnimation.init(keyPath: "position")
animation_Position.fromValue = CGPoint.init(x: margin_ViewMidPosition, y: kScreenH / 2)
animation_Position.toValue = CGPoint.init(x: kScreenW / 2, y: kScreenH / 2)
animation_Position.duration = 1.0
animation_Position.fillMode = "forwards" //只在前台
animation_Position.isRemovedOnCompletion = false //切出界面再回来动画不会停止
animation_Position.beginTime = currentTime
view_Body.layer.add(animation_Position, forKey: "positionAnimation")
let animation_Scale = CABasicAnimation.init(keyPath: "transform.scale")
animation_Scale.fromValue = NSNumber.init(value: 0.7)
animation_Scale.toValue = NSNumber.init(value: 2.0)
animation_Scale.duration = 1.0
animation_Scale.fillMode = "forwards"
animation_Scale.isRemovedOnCompletion = false
animation_Scale.beginTime = currentTime + 1.0
view_Body.layer.add(animation_Scale, forKey: "scaleAnimation")
let animation_Rotate = CABasicAnimation.init(keyPath: "transform.rotation")
animation_Rotate.toValue = NSNumber.init(value: Double.pi * 4)
animation_Rotate.duration = 1.0
animation_Rotate.fillMode = "forwards"
animation_Rotate.isRemovedOnCompletion = false
animation_Rotate.beginTime = currentTime + 2.0
view_Body.layer.add(animation_Rotate, forKey: "rotateAnimation")
}
4. 过渡动画( CATransition )
CATransition 是 CAAnimation 的子类,用于做过渡动画或者 转场 动画,能够为层提供移出屏幕和移入屏幕的动画效果。
过渡动画通过 type 设置不同的动画效果, CATransition 有多种过渡效果, 但其实 Apple 官方的SDK只提供了四种:
- fade 淡出 默认
- moveIn 覆盖原图
- push 推出
- reveal 底部显示出来
但私有API提供了其他很多非常炫的过渡动画,如 cube(立方旋转)、suckEffect(吸走)、oglFlip(水平翻转 沿y轴)、 rippleEffect(滴水效果)、pageCurl(卷曲翻页 向上翻页)、pageUnCurl(卷曲翻页 向下翻页)、cameraIrisHollowOpen(相机开启)、cameraIrisHollowClose(相机关闭)等。
注: 因 Apple 不提供维护,并且有可能造成你的app审核不通过, 所以不建议开发者们使用这些私有API.
效
