美文网首页动画
《iOS动画》读书笔记·内容层动画

《iOS动画》读书笔记·内容层动画

作者: SPIREJ | 来源:发表于2019-03-23 16:24 被阅读0次

    《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下各种常用动画类的继承关系图

    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的关键帧动画效果(前面有介绍)。ACKeyframeAnimationCAPropertyAnimation的一个子类,与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粒子发射单元,控制粒子的移动速度、方向、范围等等,这些属性可以制作酷炫的粒子特效动画

    粒子火焰效果.gif
    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

    粒子霓虹效果.gif
    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坐标系
      frame坐标系与“梯度”坐标系对应关系
    属性
    • 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,也就是线性绘制,各个颜色阶层直接的变化是线性的
    GradientLayer颜色梯度变化.gif
    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) 图层复制 - 雷达效果
    图层复制 - 雷达效果.gif
    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) 图层复制 - 加载动画效果
    图层复制 - 加载动画效果.gif
    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动画》读书笔记·转场动画

    相关文章

      网友评论

        本文标题:《iOS动画》读书笔记·内容层动画

        本文链接:https://www.haomeiwen.com/subject/hdttvqtx.html