• 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函数而言,只需在闭包中写入相关的属性及值,则可以进行对应的动画处理,例如:

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

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

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

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

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

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

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

    类似的方法调用还包括:

    1. //转场动画
    2. open class func transition(with view: UIView, duration: TimeInterval, options: UIView.AnimationOptions = [], animations: (() -> Void)?, completion: ((Bool) -> Void)? = nil)
    3. //关键帧动画
    4. 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有两个比较重要的代理方法,分别为:

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

    CABasicAnimation(基本动画)

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

    1. //CAPropertyAnimation属性,要改变的属性名称,字符串
    2. open var keyPath: String?
    3. //keyPath对应的初始值
    4. open var fromValue: Any?
    5. //keyPath对应的结束值
    6. open var toValue: Any?
    7. //keyPath的改变值
    8. open var byValue: Any?

    keyPath可以使用的key值有:

    1. transform.rotation.x 围绕x轴翻转 参数:角度 angle2Radian(5)
    2. transform.rotation.y 围绕y轴翻转 参数:同上
    3. transform.rotation.z 围绕z轴翻转 参数:同上
    4. transform.rotation 默认围绕z轴
    5. transform.scale.x x方向缩放 参数:缩放比例 1.5
    6. transform.scale.y y方向缩放 参数:同上
    7. transform.scale.z z方向缩放 参数:同上
    8. transform.scale 所有方向缩放 参数:同上
    9. transform.translation.x x方向移动 参数:x轴上的坐标 100
    10. transform.translation.y x方向移动 参数:y轴上的坐标
    11. transform.translation.z x方向移动 参数:z轴上的坐标
    12. transform.translation 移动 参数:移动到的点 (100100
    13. opacity 透明度 参数:透明度 0.5
    14. backgroundColor 背景颜色 参数:颜色 (id)[[UIColor redColor] CGColor]
    15. cornerRadius 圆角 参数:圆角半径 5
    16. borderWidth 边框宽度 参数:边框宽度 5
    17. bounds 大小 参数:CGRect
    18. contents 内容 参数:CGImage
    19. contentsRect 可视内容 参数:CGRect 值是01之间的小数
    20. hidden 是否隐藏
    21. position
    22. shadowColor
    23. shadowOffset
    24. shadowOpacity
    25. shadowRadius

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

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

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

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

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

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

    CAKeyframeAnimation(关键帧动画)

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

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

    CAAnimationGroup(组动画)

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

    1. let animation1 = CABasicAnimation(keyPath: "position")
    2. animation1.fromValue = [originalFrame!.midX, originalFrame!.midY]
    3. animation1.toValue = [window.frame.midX, window.frame.midY]
    4. animation1.duration = 2
    5. animation1.isRemovedOnCompletion = false
    6. animation1.beginTime = 0.0
    7. animation1.fillMode = .forwards
    8. let animation2 = CABasicAnimation(keyPath: "transform.scale.x")
    9. animation2.fromValue = originalFrame!.width / imageView.frame.width
    10. animation2.toValue = 1.0
    11. animation2.duration = 2
    12. animation2.isRemovedOnCompletion = false
    13. animation2.beginTime = 0.0
    14. animation2.fillMode = .forwards
    15. let animation3 = CABasicAnimation(keyPath: "transform.scale.y")
    16. animation3.fromValue = originalFrame!.height / imageView.frame.height
    17. animation3.toValue = 1.0
    18. animation3.duration = 2
    19. animation3.isRemovedOnCompletion = false
    20. animation3.beginTime = 0.0
    21. animation3.fillMode = .forwards
    22. let group = CAAnimationGroup()
    23. group.animations = [animation1, animation2, animation3]
    24. group.duration = 2
    25. group.isRemovedOnCompletion = false
    26. layer.add(group, forKey: "animation")

    CATransition(转场动画)

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

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

    • subtype:动画过渡方向

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

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

    1. let animation = CATransition()
    2. animation.type = .fade
    3. animation.subtype = .fromRight
    4. animation.startProgress = 0
    5. layer.add(animation, forKey: "animation")

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

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

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

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

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

    1. CATransaction.begin() //动画属性的入栈
    2. CATransaction.setDisableActions(true) //设置隐藏动画
    3. // code that modifies the properties of one or more views.
    4. 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核心动画高级技巧 · 看云

  • 相关阅读:
    Linux权限
    Redisson分布式锁 --- 源码分析
    征文|@程序员,快来解锁过“中秋”的正确姿势!
    课程设计 | 通讯录管理系统
    【docker】dockerfile优化镜像大小
    HBase 的安装与部署
    套餐内商品的排列顺序(字符串的排列),剑指offer,力扣
    Redis---第一篇
    带符号整数
    Elasticsearch个人学习笔记
  • 原文地址:https://blog.csdn.net/weixin_41111088/article/details/127038004