iOS动画相关

App内的动画对于用户体验的提升很重要,在iOS实际开发中常用的动画主要包括两大类,UIView动画和核心动画(Core Animation),Core Animation又分出来CAAnimationGroup(组动画),CABasicAnimation(基本动画),CAKeyframeAnimation(关键帧动画)以及CATransition(转场动画)。

1、UIView动画

UIView类提供了大量的动画API,使用这些UIView提供的类方法我们可以对View的相关属性做动画,包括position,size,bounds&frame,center,backgroundColor,alpha,transformation。对于UIView的animate函数而言,只需在闭包中写入相关的属性及值,则可以进行对应的动画处理,例如:

UIView.animate(withDuration: 0.3, delay: 0.0, options:[UIView.AnimationOptions.allowUserInteraction, UIView.AnimationOptions.beginFromCurrentState], animations: { () -> Void in
      // set your view's attribute you want to change
}) { (_) -> Void in
     //do something after animation completed
}

其中,相关属性说明如下:

  • duration :整个动画持续的时间

  • delay:动画在多久之后开始,值为 0 表示代码执行到这里后动画立刻开始

  • options:一些有关动画的设置,包括淡入淡出,是否允许交互,转场效果等都在options设置

  • animations:在这个 block 中写入你想要执行的代码即可。block 中对视图的动画属性所做的改变都会生成动画

  • completion:动画完成后会调用,finished 表示动画是否成功执行完毕。可以将动画执行完成后需要执行的代码写在这里

类似的方法调用还包括:

//转场动画
open class func transition(with view: UIView, duration: TimeInterval, options: UIView.AnimationOptions = [], animations: (() -> Void)?, completion: ((Bool) -> Void)? = nil)
//关键帧动画
open class func animateKeyframes(withDuration duration: TimeInterval, delay: TimeInterval, options: UIView.KeyframeAnimationOptions = [], animations: @escaping () -> Void, completion: ((Bool) -> Void)? = nil)

2 Core Animation

 

CAAnimation是所有动画对象的父类,负责控制动画的持续时间和速度,是个抽象类,不能直接使用,应该使用继承于CAAnimation的四个子类来实现相关动画。其中关于CAAnimation的一些比较重要的属性有:

  • duration:动画的持续时间

  • repeatCount:默认为0,重复次数,无限循环可以设置greatestFiniteMagnitude

  • repeatDuration:重复时间

  • autoreverses:是否倒退,如果为true,则执行动画后倒退回动画前

  • fillMode:默认为.remove,代表动画执行完毕后就从图层上移除,如果想让图层保持显示动画执行后的状态,那就设置fillMode为.forwards(.backwards, .both分别代表动画前以及动画中间的某一个状态)

  • beginTime:可以用来设置动画延迟执行时间,若想延迟2s,就设置为CACurrentMediaTime()+2,CACurrentMediaTime()为图层的当前时间

  • Speed:速度控制函数,控制动画运行的节奏

  • delegate:动画代理

其中CAAnimation有两个比较重要的代理方法,分别为:

@protocol CAAnimationDelegate <NSObject>
  //动画已经开始
- (void)animationDidStart:(CAAnimation *)anim;
	//动画已经结束或者动画已经从添加的layer中移除
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;

CABasicAnimation(基本动画)

继承于CAPropertyAnimation,用于绘制基础的两帧动画(初始帧跟结束帧),主要属性:

//CAPropertyAnimation属性,要改变的属性名称,字符串
open var keyPath: String?
//keyPath对应的初始值
open var fromValue: Any?
//keyPath对应的结束值
open var toValue: Any?
//keyPath的改变值
open var byValue: Any?

keyPath可以使用的key值有:

transform.rotation.x 围绕x轴翻转 参数:角度 angle2Radian(5) 
transform.rotation.y 围绕y轴翻转 参数:同上 
transform.rotation.z 围绕z轴翻转 参数:同上 
transform.rotation 默认围绕z轴 
transform.scale.x x方向缩放 参数:缩放比例 1.5 
transform.scale.y y方向缩放 参数:同上 
transform.scale.z z方向缩放 参数:同上 
transform.scale 所有方向缩放 参数:同上 
transform.translation.x x方向移动 参数:x轴上的坐标 100 
transform.translation.y x方向移动 参数:y轴上的坐标 
transform.translation.z x方向移动 参数:z轴上的坐标 
transform.translation 移动 参数:移动到的点 (100,100) 
opacity 透明度 参数:透明度 0.5 
backgroundColor 背景颜色 参数:颜色 (id)[[UIColor redColor] CGColor] 
cornerRadius 圆角 参数:圆角半径 5 
borderWidth 边框宽度 参数:边框宽度 5 
bounds 大小 参数:CGRect 
contents 内容 参数:CGImage 
contentsRect 可视内容 参数:CGRect 值是0~1之间的小数 
hidden 是否隐藏 
position 
shadowColor 
shadowOffset 
shadowOpacity 
shadowRadius

随着动画的进行,在长度为duration的持续时间内,keyPath相应属性的值从fromValue渐渐地变为toValue。值得注意的是,以上三个属性均为可选值,三者应满足fromValue + byValue = toValue,设置值时应满足最少两个值不为nil,否则若:

  • fromValue不空:从fromValue到属性的当前值之间插值

  • toValue不空:从属性的当前值到toValue之间插值

  • byValue不空:从属性的当前值插值到当前值加上byValue作为终值

  • 三者全空:从属性的先前值到当前值进行插值

let animationOpacity = CABasicAnimation(keyPath: "opacity")
animationOpacity.fromValue = NSNumber(value: 1.0)
animationOpacity.toValue = NSNumber(value: 0)
animationScale.duration = 0.5
animationOpacity.fillMode = .forwards

CAKeyframeAnimation(关键帧动画)

继承于CAPropertyAnimation,与CABasicAnimation不同的是,关键帧动画存储了在动画过程中的一系列帧,用于实现复杂动画过程。主要属性有:

//保存动画过程中数值的数组,里面的元素称为“关键帧”(keyframe)。动画对象会在指定的时间(duration)内,依次显示values数组中的每一个关键帧
open var values: [Any]?
//代表路径可以设置一个CGPathRef、CGMutablePathRef,让图层按照路径轨迹移动。path只对CALayer的anchorPoint和position起作用。如果设置了path,那么values将被忽略
open var path: CGPath?
//可以为对应的关键帧指定对应的时间点,其取值范围为0到1.0,keyTimes中的每一个时间值都对应values中的每一帧。如果没有设置keyTimes,各个关键帧的时间是平分的
open var keyTimes: [NSNumber]?
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
layer.add(animation, forKey: "animation")

CAAnimationGroup(组动画)

CAAnimationGroup是CAAnimation的子类,可以保存一组动画对象,可以保存基础动画、关键帧动画,数组中的所有动画对象可以同时并发运行,也可以设置为串行连续动画。

let animation1 = CABasicAnimation(keyPath: "position")
animation1.fromValue = [originalFrame!.midX, originalFrame!.midY]
animation1.toValue = [window.frame.midX, window.frame.midY]
animation1.duration = 2
animation1.isRemovedOnCompletion = false
animation1.beginTime = 0.0
animation1.fillMode = .forwards

let animation2 = CABasicAnimation(keyPath: "transform.scale.x")
animation2.fromValue = originalFrame!.width / imageView.frame.width
animation2.toValue = 1.0
animation2.duration = 2
animation2.isRemovedOnCompletion = false
animation2.beginTime = 0.0
animation2.fillMode = .forwards

let animation3 = CABasicAnimation(keyPath: "transform.scale.y")
animation3.fromValue = originalFrame!.height / imageView.frame.height
animation3.toValue = 1.0
animation3.duration = 2
animation3.isRemovedOnCompletion = false
animation3.beginTime = 0.0
animation3.fillMode = .forwards

let group = CAAnimationGroup()
group.animations = [animation1, animation2, animation3]
group.duration = 2
group.isRemovedOnCompletion = false

layer.add(group, forKey: "animation")

CATransition(转场动画)

CATransition是CAAnimation的子类,用于做转场动画,能够为层提供移出屏幕和移入屏幕的动画效果。UINavigationController就是通过CATransition实现了将控制器的视图推入屏幕的动画效果,相关属性有:

  • type:动画过渡类型,Apple提供了四种动画过渡类型,为fade(淡出)、moveIn(覆盖原图)、push(推出)以及reveal(从底部显示出来)

  • subtype:动画过渡方向

  • startProgress:动画起点(在整体动画的百分比,范围0~1)

  • endProgress:动画终点(在整体动画的百分比,范围0~1)

let animation = CATransition()
animation.type = .fade
animation.subtype = .fromRight
animation.startProgress = 0
layer.add(animation, forKey: "animation")

补充:每一个UIView内部都默认关联着一个CALayer,称为root layer,所有的非root layer,也就是手动创建的CALayer对象,都存在隐式动画,当对非root layer的部分属性进行修改时,默认会自动产生一些动画效果,而这些属性成为Animation Properties(可动画属性),常见可动画属性:

bounds:用于设置CALayer的宽度和高度。修改这个属性会产生缩放动画
backgroundColor:用于设置CALayer的背景色。修改这个属性会产生背景色的渐变动画
position:用于设置CALayer的位置。修改这个属性会产生平移动画

这里引入一个事务(Transaction)的概念,Core Animation用来包含一系列属性动画集合的机制,通过指定事务来改变图层的可动画属性,而这些改变不是立刻发生,只有在事务被提交的时候才启动一个动画过度到新值,任何可以做动画的图层属性都会被添加到栈顶的事务。

现在再来考虑隐式动画,其实是Core Animation在每个RunLoop周期中会自动开始一次新的事务,即使你不显式的使用CATransaction.begin()开始一次事务,任何在一次RunLoop运行时循环中属性的改变都会被集中起来,执行默认0.25秒的动画。

可以通过以下方法关闭隐式动画:

CATransaction.begin() //动画属性的入栈
CATransaction.setDisableActions(true) //设置隐藏动画
// code that modifies the properties of one or more views.
CATransaction.commit() //动画属性的出栈

参考:

Apple Developer Documentation

iOS动画全面解析 - 掘金

https://www.jianshu.com/p/f2def3da931f

https://www.jianshu.com/p/9fa025c42261

https://www.jianshu.com/p/5abc038e4d94

iOS动画-CALayer隐式动画原理与特性 - 腾讯云开发者社区-腾讯云

https://www.jianshu.com/p/c22918a5e7ca

iOS UIView Animation - Keyframe | 程序员说

https://shixiong.name/2016/11/03/bezier-zhibei/index.html

10.2 自定义缓冲函数 · ios核心动画高级技巧 · 看云

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值