内容层动画(layer层 Core Animation 核心动画)

核心动画简介:
核心动画直接作用于layer层;在后台线程执行,不阻塞主线程


2FD30689-8D35-4B86-AB3A-5FCBD7BC65C1.png

一、CABasicAnimation (针对layer的属性进行动画效果)
1、位置动画:

override func viewWillAppear(_ animated: Bool) {
       super.viewWillAppear(animated)
       let animation:CABasicAnimation = CABasicAnimation()
       animation.keyPath = "position"
       animation.duration = 2;
       //下面代码表示动画结束后,保持结束时的状态
       animation.fillMode = CAMediaTimingFillMode.forwards
       animation.isRemovedOnCompletion = false
       animation.toValue = NSValue(cgPoint: CGPoint(x: 300, y: 600))
       layer?.add(animation, forKey: nil)
   }

其他属性与上面一样,只要把要做的动画属性赋值给 animation.duration 即可


0B03AE1D-168C-4382-9315-295D6C410158.png

CAB3D1BA-6CD9-41F9-8D7B-5273E9D90CB5.png

二、CAKeyframeAnimation 关键帧动画类
1、属性介绍:values : 一系列位置信息; keyTimes : 默认是均匀播放的,取值范围:0-1;
path : 绘制动画路径
2、介绍下 淡入淡出动画

  class ViewController: UIViewController {
    var myView:UIView?
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor.white
        let myV = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
        myV.center = view.center
        myV.backgroundColor = UIColor.blue
        view.addSubview(myV)
        myView = myV;

        let animation:CAKeyframeAnimation = CAKeyframeAnimation()
        animation.duration = 10
        animation.keyPath = "opacity"
        let values:[NSNumber] = [NSNumber(value: 0.95),NSNumber(value: 0.90),NSNumber(value: 0.85),NSNumber(value: 0.80),
        NSNumber(value: 0.75),NSNumber(value: 0.70),NSNumber(value: 0.65),NSNumber(value: 0.60),NSNumber(value: 0.50),NSNumber(value: 0.40),NSNumber(value: 0.30),NSNumber(value: 0.20)]
        
        animation.values = values
        animation.fillMode = CAMediaTimingFillMode.forwards
        animation.isRemovedOnCompletion = false
        myV.layer.add(animation, forKey: nil)
    }
}

其他属性动画类似,修改values和keypath 即可

3、任意路径动画

  let animation:CAKeyframeAnimation = CAKeyframeAnimation()
        animation.duration = 10
        let path = CGMutablePath()
        path.move(to: CGPoint(x: 40, y: 40))
        path.addLine(to: CGPoint(x: 300, y: 300))
        path.addLine(to: CGPoint(x: 40, y: 600))
        animation.path = path
        animation.keyPath = "position";
        animation.fillMode = CAMediaTimingFillMode.forwards
        animation.isRemovedOnCompletion = false
        myV.layer.add(animation, forKey: nil)

4、 CAAnimationGroup 组合动画介绍

       let ca1 = CABasicAnimation(keyPath:"transform.rotation")
       ca1.toValue = Double.pi
        let scale = CABasicAnimation(keyPath: "transform.scale")
        scale.toValue = 0.1
        let move = CABasicAnimation(keyPath: "transform.translation")
        move.toValue = NSValue(cgPoint: view.center)
        let animaGroup = CAAnimationGroup()
        animaGroup.animations = [ca1,scale,move]
        animaGroup.duration = 6
        animaGroup.fillMode = CAMediaTimingFillMode.forwards
        animaGroup.isRemovedOnCompletion = false
        myV.layer.add(animaGroup, forKey: nil)

三、综合案例的实现
1、水纹按钮动画效果的实现
主要分成胰腺癌5个主要模块
1)UIBUtton的坐标获取
2)Draw 圆形绘制模块
3)定时器刷新
4)其他模块
5)调用模块
代码如下:代码主要在自定义button中实现

import UIKit
class MyButton: UIButton {
    var timer:Timer?
    var touchPoint:CGPoint?
    var viewRadius:CGFloat = 0
    var targetAnimationColor:UIColor = UIColor(red: 216.0/255.0, green: 114.0/255.0, blue: 213.0/255.0, alpha: 0.8)
    
    var countNum:Int = 0
    
    override init(frame: CGRect) {
        super.init(frame:frame)
        backgroundColor = UIColor(red: 50.0/255.0, green: 185.0/255.0, blue: 170.0/255.0, alpha: 1.0)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    //此处禁用按钮点击事件,获取点击位置,
    func starButtonAnimation(send:UIButton,event:UIEvent) {
        isUserInteractionEnabled = false;
        let button:UIView = send as UIView
        let touchSet:NSSet = event.touches(for: button)! as NSSet
        var touchArray:[AnyObject] = touchSet.allObjects as [AnyObject]
        let touch1:UITouch = touchArray[0] as! UITouch
        let point:CGPoint = touch1.location(in: button)
        touchPoint = point
        timer = Timer.scheduledTimer(timeInterval: 0.2, target: send, selector: #selector(timeaction), userInfo: nil, repeats: true)
        
        RunLoop.main.add(timer!, forMode: RunLoop.Mode.common)
        
        
    }
    //定时器方法,定时刷新上下重新绘制
    @objc func timeaction() {
        countNum += 1
        let dismissTime:DispatchTime = DispatchTime.now() + Double(bitPattern: 0*NSEC_PER_SEC)
        DispatchQueue.main.asyncAfter(deadline: dismissTime) {
            self.viewRadius += 4
            self.setNeedsDisplay()
        }
        if countNum>70 {
            countNum = 0
            viewRadius = 0
            timer?.invalidate()
            DispatchQueue.main.asyncAfter(deadline: dismissTime) {
                self.viewRadius = 0
                self.setNeedsDisplay()
            }
            self.isUserInteractionEnabled = true
        }
    }
    //绘制圆
    override func draw(_ rect: CGRect) {
        let ctx:CGContext = UIGraphicsGetCurrentContext()!
        let endAngle:CGFloat = CGFloat(Double.pi*2)
        ctx.addArc(center: touchPoint ?? center, radius:viewRadius , startAngle: 0, endAngle: endAngle, clockwise: false)
        let stockColor:UIColor = targetAnimationColor
        stockColor.setStroke()
        stockColor.setFill()
        ctx.fillPath()
    }
}
//以上为自定义按钮的实现内用,下面我控制器内使用的代码
class ViewController: UIViewController {
    var myView:UIView?
    var image:UIImageView?
    var myBtn:MyButton?
    override func viewDidLoad() {
        super.viewDidLoad()
        let mBtn:MyButton = MyButton(frame: CGRect(x: 0, y: 0, width: 200, height: 100))
        view.addSubview(mBtn)
        mBtn.center = view.center
        myBtn = mBtn
        mBtn.backgroundColor = UIColor.yellow
        mBtn.setTitle("登录", for: UIControl.State.normal)
        mBtn.addTarget(self, action: #selector(buttonClick(_:event:)), for: UIControl.Event.touchUpInside)
    
    }
    @objc  func buttonClick(_ sender:UIButton,event:UIEvent) {
        let  bt:MyButton = sender as! MyButton
        bt.starButtonAnimation(send: sender, event: event)
        
    }
}

四、CAShapeLayer 主要用于各种图形绘制(如柱状图、饼状图、股票的K线图等等)
都是基于贝济埃曲线绘制,首先来了解什么是贝济埃曲线
1、贝济埃曲线,它是依据四个位置任意点的坐标绘制出一条光滑的曲线(如四个顶点A、B、C、D,其中A为绘制起点,D为终点,在A处设置一条曲线,保证曲线的切刚好经过B,同时在D出设置一条曲线,刚好保证曲线经过C点)
2、贝济埃曲线的使用步骤:
1)创建一个贝济埃曲线对象(UIBezierPath)
2) 设置曲线的各种属性:颜色、线条粗细等
3)设置曲线起始点
4)开始绘制
3、UIBezierPath 的属性介绍
1)线条宽度 lineWidth
2) 线条拐角 lineCapStyle (设置线条首位形状的)
lineJoinStyle 用于设置两条线段衔接处的

 func drawLine() {
        //设置路径
        let path = UIBezierPath()
        path.move(to: CGPoint(x: 20, y: 40))
        path.addLine(to: CGPoint(x: 200, y: 200))
        path.addLine(to: CGPoint(x: 40, y: 400))
        path.lineCapStyle = CGLineCap.round
        path.close()
        //开始绘画
        let shapeLayer = CAShapeLayer()
        shapeLayer.lineWidth = 10
        shapeLayer.lineCap = .round
        shapeLayer.lineJoin = .round
        shapeLayer.strokeColor = UIColor.red.cgColor
        shapeLayer.fillColor = UIColor.yellow.cgColor
        shapeLayer.path = path.cgPath
        view.layer.addSublayer(shapeLayer)
    }

     4、绘制动态图表
        1)折线图
        import UIKit
class MyChartLine: UIView {
    var charLine:CAShapeLayer = CAShapeLayer()
    var pathAnimation:CABasicAnimation = CABasicAnimation()
    init(frame: CGRect,path:UIBezierPath) {
        super.init(frame: frame)
        backgroundColor = UIColor.white
        clipsToBounds = true
        charLine.lineCap = .round
        charLine.lineJoin = .round
        charLine.fillColor = UIColor.white.cgColor
        charLine.strokeColor = UIColor.green.cgColor
        charLine.lineWidth = 3
       //这个属性设置是为了,让线不是一次性绘画完成
        charLine.strokeEnd = 0.0
        charLine.path = path.cgPath
        layer.addSublayer(charLine)
        pathAnimation.keyPath = "strokeEnd"
        pathAnimation.timingFunction = CAMediaTimingFunction(name:CAMediaTimingFunctionName.linear)
        pathAnimation.fromValue = 0.0
        pathAnimation.toValue = 1.0
        pathAnimation.autoreverses = false
        pathAnimation.duration = 5
        pathAnimation.fillMode = CAMediaTimingFillMode.forwards
        pathAnimation.isRemovedOnCompletion = false
        
        charLine.add(pathAnimation, forKey: nil)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

以上代码,是用于折线的view的内部代码,实现了line和动画,外界只要传个路径就可以

import UIKit
class MyController1: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor.white
        let path:UIBezierPath = UIBezierPath()
        path.move(to: CGPoint(x: 0, y: 500))
        path.addLine(to: CGPoint(x: 40, y: 60))
        path.addLine(to: CGPoint(x: 140, y: 300))
        path.addLine(to: CGPoint(x: 190, y: 290))
        path.addLine(to: CGPoint(x: 240, y: 360))
        path.addLine(to: CGPoint(x: 290, y: 180))
        path.addLine(to: CGPoint(x: 360, y: 60))
        let myLine:MyChartLine = MyChartLine(frame: CGRect(x:0, y: 500, width: UIScreen.main.bounds.size.width, height: 400), path: path)
        view.addSubview(myLine)
    }
}

你可能感兴趣的:(内容层动画(layer层 Core Animation 核心动画))