iOS动画总结

iOS动画实现方式和效果

iOS动画学习路程 :一开始学习肯定需要通过网络搜索,逐渐对动画的架构、常用API、常用效果进行全面的认识;熟悉动画的各种API和实现一些效果后,达到可以通过“搬砖+修改”来进行快速开发;

根据动画在iOS中实现的位置划分:

  • 显示层动画效果:利用UIView图层显示的效果实现各种动画,常用的效果有:位置动画、位移动画、颜色动画、淡入淡出动画、旋转动画、缩放动画、几何形状动画、另外还有关键帧动画、逐帧动画等;
  • 内容层动画效果:利用Layer图层实现的动画:CAEmitterCell粒子动画、CAGradientLayer扫描动画、CAShapeLayer图表类动画、CAReplicatorLayer图层快速复制动画等;
  • 3D动画效果:3D动画效果以矩阵变换为基础,利用x、y、z与变换矩阵相互作用实现各种效果;
  • 转场动画效果:常用于多视图场景下视图切换,如:水滴、翻页、波纹效果或自定义转场动画;

显示层动画

UIView中的动画都是通过修改当前UI控件的各种属性来实现的动画效果;
关键帧动画的实现与UIView的动画合集提到的动画效果有些不同,关键帧只需要设置动画的几个关键的显示帧;

显示层初级动画合集
1. 动画分析方法展示过程

动画起始阶段、动画进行阶段、动画结束阶段;
实现动画可以有两种方法:1.闭包形式;2.方法形式; 下面是简单示例:

var loginButton: UIButton?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        loginButton = UIButton(frame: CGRect(x: -400, y: 300, width: self.view.frame.width - 40, height: 50))
        loginButton?.backgroundColor = UIColor(red: 50/255.0, green: 185/255.0, blue: 170/255.0, alpha: 1.0)
        loginButton?.setTitle("登录", for: UIControl.State.normal)
        view.addSubview(loginButton!)
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        // 使用闭包形式
        UIView.animate(withDuration: 1.0) {
            self.loginButton?.frame = CGRect(x: 20, y: 300, width: self.view.frame.width - 40, height: 50)
        }
        
        // 使用方法形式
        UIView.beginAnimations(nil, context: nil)
        UIView.setAnimationDuration(1)
        loginButton?.frame = CGRect(x: 20, y: 300, width: view.frame.width - 40, height: 50)
        UIView.commitAnimations()
    }
2. UIView视图中常见动画的属性
  • 位置属性:frame bounds center :可以用于修改移动位置和拉伸收缩效果;
  • 透明度属性:alpha:实现淡入淡出效果;
  • Layer属性:圆形渐变、边框颜色、阴影、3D等高级动画效果;
  • transform属性:该属性继承于CGAffineTransform,是核心绘图框架与UIView之间的桥梁,可以借助实现很多高级动画效果;最常用的动画分别是缩放、旋转和位移;
3. 动画常用属性
  • setAnimationDelay
  • setAnimationDuration
  • setAnimationCurve : 设置动画加速减速效果(参数枚举:EaseInOut、EaseIn、EaseOut、Linear)
  • setAnmationsEnabled
  • setAnimationRepeatCount
  • setAnimationRepeatAutoreverses
4. 动画回调方法的使用
  • delegate回调方法
  • setAnimationDidStopSelector自定义回调方法
5. 初级动画效果合集

重点:
1.掌握UIView显示层常用动画效果合集:位置、几何形状、旋转、缩放、淡入淡出、颜色渐变等;以及CoreGraphics中的CGAffineTransform属性的了解;
2.掌握动画效果的组合使用;
3.理解抽奖转盘动画效果的实现方法;

6. 转盘效果
import UIKit

class ZhuanPanViewController: UIViewController {

    var zhuanpan: UIImageView?
    
    var rotationIndex: NSInteger = 0
    
    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = UIColor(red: 246/255.0, green: 246/255.0, blue: 246/255.0, alpha: 1.0)
        // Do any additional setup after loading the view.
        
        zhuanpan = UIImageView.init(frame: CGRect(origin: CGPoint(x: view.bounds.origin.x, y: view.bounds.origin.y), size: CGSize(width: 250, height: 250)))
        zhuanpan?.contentMode = UIView.ContentMode.scaleAspectFill
        zhuanpan?.center = view.center
        zhuanpan?.image = UIImage.init(named: "zhuanpan")
        view.addSubview(zhuanpan!)
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        animationStop()
    }
    
    @objc func animationStop() {
        
        UIView.beginAnimations(nil, context: nil)
        UIView.setAnimationDelegate(self)
        UIView.setAnimationDidStop(#selector(animationStop))
        UIView.setAnimationDuration(0.4)
        UIView.setAnimationCurve(UIView.AnimationCurve.linear)
        
        let angle:CGFloat = CGFloat(Double.pi/2)
        rotationIndex += 1
        
        zhuanpan?.transform = CGAffineTransform(rotationAngle: CGFloat(rotationIndex) * angle)
        
        UIView.commitAnimations()
    }
}

效果如图:
转盘旋转

显示层关键帧动画
1. 实现原理

关键帧动画主要使用在通过动画的几张关键图片描述整个动画的效果;

2. 关键帧的属性

options: 描述动画执行效果,枚举类型

  • CalculationModeLinear: 默认,动画匀速线性执行
  • CalculationModeDiscrete:
  • CalculationModeModePaced:
  • CalculationModeModeCubic:
  • CalculationModeModeCubicPaced:
3. 动画中常用关键帧的设置
import UIKit

class AnimateKeyViewController: UIViewController {

    var zhuanpan: UIImageView?
    
    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = UIColor(red: 246/255.0, green: 246/255.0, blue: 246/255.0, alpha: 1.0)
        // Do any additional setup after loading the view.
        
        zhuanpan = UIImageView.init(frame: CGRect(x: 100, y: 100, width: 80, height: 80))
        zhuanpan?.contentMode = UIView.ContentMode.scaleAspectFill
        zhuanpan?.image = UIImage.init(named: "zhuanpan")
        view.addSubview(zhuanpan!)
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        // 关键帧动画
        UIView.animateKeyframes(withDuration: 2.0, delay: 0, options: UIView.KeyframeAnimationOptions.calculationModeLinear, animations: {
            
            // 第一帧
            UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 1/2, animations: {
                self.zhuanpan?.frame = CGRect(x: 120, y: 120, width: 100, height:100)
            })
            
            // 第二帧
            UIView.addKeyframe(withRelativeStartTime: 1/2, relativeDuration: 1/2, animations: {
                self.zhuanpan?.frame = CGRect(x: 140, y: 140, width: 130, height: 130)
            })
            
        }) { (animation) in
            print("完成")
        }
    }
}
显示层逐帧动画
1. 实现原理

逐帧动画实现的动画效果就是将图片一帧一帧的逐帧渲染;使用定时器、CADisplayLink、Draw等方法实现逐帧动画;

2. 基于NSTimer和CADisplayLink实现方式的区别

基于NSTimer的实现经常使用在动画帧率不高并且帧率之间的时间间隔并不是特别严格的情况;
基于CADisplayLink的帧刷新频率高达每秒60帧且非常精准;
iOS设备的屏幕刷新频率默认是60Hz,而CADisplayLink可以保持和屏幕刷新率相同的频率将内容渲染在屏幕上,且精度非常高。

3.CADisplayLink的实现方法

CADisplayLink在使用时需要注册到runloop中,每当刷帧频率达到的时候runloop回向CADisplayLink指定的target发送一次指定的selector消息;

import UIKit

class NSTimerViewController: UIViewController {

    var zhuanpan: UIImageView?
    
    var index: NSInteger = 0
    
    var displaylink: CADisplayLink?
    
    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = UIColor(red: 246/255.0, green: 246/255.0, blue: 246/255.0, alpha: 1.0)
        // Do any additional setup after loading the view.
        
        zhuanpan = UIImageView.init(frame: CGRect(x: 100, y: 100, width: 80, height: 80))
        zhuanpan?.contentMode = UIView.ContentMode.scaleAspectFill
        zhuanpan?.image = UIImage.init(named: "zhuanpan")
        view.addSubview(zhuanpan!)
        
        displaylink = CADisplayLink.init(target: self, selector: #selector(refushImage))
        displaylink?.preferredFramesPerSecond = 1
        displaylink?.add(to: RunLoop.current, forMode: RunLoop.Mode.default)
    }
    
    @objc func refushImage() {
        zhuanpan?.image = UIImage(named: "\(index).png")
        
        index += 1
        if index == 67 {
            index = 0
        }
    }
}
4.基于draw方法的逐帧动画

UIView中有一个draw方法,当创建一个新的view时,会自动生成一个draw方法,且该方法可以被重写,一旦draw方法被调用,Cocoa会创建一个图形上下文,在图形上下文中所有操作会反应在UIView界面上。按照这个思路,如果定期调用draw方法绘制新的内容,就可以实现逐帧动画效果了;
draw()方法触发的机制:1. 使用addSubview会触发layoutSubviews; 2.使用view的frame属性会触发layoutSubviews; 3.直接调用setLayoutSubviews会触发layoutSubviews;
使用draw方法的时候不需要图片素材,可用性较好,这个是NSTimer或者CADisplayLink所不能比的;

import UIKit

class BlackHoleViewController: UIViewController {

    var blackHole: BlackHoleView?
    
    var index: Float = 0
    var timer: Timer?
    
    override func viewDidLoad() {
        super.viewDidLoad()

        blackHole = BlackHoleView()
        blackHole?.frame = UIScreen.main.bounds
        blackHole?.backgroundColor = UIColor.gray
        view.addSubview(blackHole!)
        
        timer = Timer.scheduledTimer(timeInterval: 1.0/30, target: self, selector: #selector(refreshImage), userInfo: nibName, repeats: true)
    }
    
    // 刷新图片
    @objc func refreshImage() {
        
        // 半径赋值
        blackHole?.blackHoleIncrease(index)
        
        index += 1
    }
}

// View视图
class BlackHoleView: UIView {
    
    // 黑洞半径
    var blackHoleRadius: Float = 0
    
    // 半径赋值,重绘
    func blackHoleIncrease(_ radius: Float) {
        blackHoleRadius = radius
        self.setNeedsDisplay()  // 会调用draw方法
    }
    
    override func draw(_ rect: CGRect) {
        // 获取当前绘图上下文
        let ctx: CGContext = UIGraphicsGetCurrentContext()!
        // 绘制圆形  clockwise:true:顺时针绘制 false:逆时针绘制
        ctx.addArc(center: CGPoint(x: self.center.x, y: self.center.y), radius: CGFloat(blackHoleRadius), startAngle: 0, endAngle: CGFloat(Double.pi * 2), clockwise: false)
        // 开始绘制
        ctx.fillPath()
    }
}
5.GIF动画效果

重点:掌握GIF图像的分解和合成与展示方式;
GIF图片的本质是由多帧静态图像按照动作发生的时间连续顺序组成的图片序列整体;
可以通过单帧图像合成GIF或者对GIF进行单帧分解;
GIF的合成与分解是由iOS图像处理核心框架ImageIO来对GIF文件格式进行解析,并将解析后的数据转换成一帧帧的图片输出;

分解过程
  • 本地读取GIF图,转为NSData数据类型;
  • 将NSData作为ImageIO模块的输入;
  • 获取ImageIO的输出数据: UIImage;
  • 将获取到的UIImage存储为JPG或PNG保存;
代码实现

内容层动画

内容层动画具有和显示层动画类似的初级动画效果,但除此之外,利用内容层的一些特殊属性可以实现高级效果:环形动画、圆角动画等;
重点:
掌握UIView显示层动画和CALayer内容层动画的区别;
理解Core Animation核心动画架构;
掌握CALayer内容层动画合集;

UIView显示层动画和CALayer内容层动画的区别:

  • UIView继承UIResponder,可以处理响应事件,CALayer继承NSObject,只负责内容的创建和绘制;
  • UIView负责内容的管理,CALayer负责内容的绘制;
  • UIView的位置属性只有:frame bounds center,而CALayer除了这些还有anchorPoint position;
  • 通过修改CALayer可以实现UIView无法实现的很多高级功能;

Core Animation为iOS核心动画,来自QuartzCore.framework框架,其特点:

  • 直接作用于CALayer图层,非UIView;
  • Core Animation的执行过程在后台执行,不阻塞主线程;
  • 可以利用CALayer绝大多数属性制作高级动画效果;

Core Animation各种常用动画类的继承关系:
核心动画类结构
CAMediaTiming: protocol 动画公共属性类;
CAAnimation:用于实现动画的委托代理方法:动画开始和结束事件;
CAPropertyAnimation:属性动画,分为基础动画和关键帧动画;
CAAnimationGroup:组合动画;
CATransition:转场动画,用于视图控制器或者多个View之间的视图切换场景;

CABasicAnimation动画效果

位置动画:position transform.translation.x transform.translation.y transform.translation.z
缩放动画:transform.scale.x transform.scale.y
旋转动画:transform.rotation
颜色动画:backgroundColor borderColor
淡入淡出动画:opacity
高级动画: 圆角动画: cornerRadius 边框动画:borderWidth 阴影动画:shadowOffset

1.位置动画
override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        // 位置动画
        let animation: CABasicAnimation = CABasicAnimation()
        animation.keyPath = "position"
        // x坐标不变
        let positionX: CGFloat = (loginButton?.frame.origin.x)! + (loginButton?.frame.size.width)! * 0.5
        // y坐标 + 100
        let positionY: CGFloat = (loginButton?.frame.origin.y)! + (loginButton?.frame.size.height)! * 0.5 + 100
        animation.toValue = NSValue(cgPoint: CGPoint(x: positionX, y: positionY))
        animation.duration = 2.0
        animation.isRemovedOnCompletion = false
        loginButton?.layer.add(animation, forKey: nil)
    }
  • position属性与frame换算公式:
    换算公式
  • toValue属性表明改变了控件的位置,需要给一个新的position,而byValue表明在控件原来的位置基础上,沿x y移动了多少;等同于: animation.byValue = NSValue(cgPoint: CGPoint(x: 0, y: 100)) ;
2.缩放动画
override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        // 缩放动画
        let animation: CABasicAnimation = CABasicAnimation()
        animation.keyPath = "transform.scale.x"
        animation.duration = 2.0
        animation.fromValue = 1.0
        animation.toValue = 0.8
        animation.isRemovedOnCompletion = false
        loginButton?.layer.add(animation, forKey: nil)
    }
3.旋转动画
override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        // 旋转动画
        let animation: CABasicAnimation = CABasicAnimation()
        animation.keyPath = "transform.rotation"
        animation.duration = 2.0
        animation.toValue = 3.14/2  // 90度
        animation.isRemovedOnCompletion = false
        loginButton?.layer.add(animation, forKey: nil)
    }
4.位移动画
override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        // 位移动画
        let animation: CABasicAnimation = CABasicAnimation()
        animation.keyPath = "transform.translation.y"
        animation.duration = 2.0
        animation.toValue = 100   // 向下移动100
        animation.isRemovedOnCompletion = false
        loginButton?.layer.add(animation, forKey: nil)
    }
5.圆角动画
override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        // 圆角动画
        let animation: CABasicAnimation = CABasicAnimation()
        animation.keyPath = "cornerRadius"
        animation.duration = 2.0
        animation.toValue = 15    // 圆角半径是15
        animation.isRemovedOnCompletion = false
        loginButton?.layer.add(animation, forKey: nil)
    }
6.边框动画
override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        loginButton?.layer.borderColor = UIColor.gray.cgColor
        loginButton?.layer.cornerRadius = 10.0
        
        // 边框动画
        let animation: CABasicAnimation = CABasicAnimation()
        animation.keyPath = "borderWidth"
        animation.duration = 2.0
        animation.toValue = 10
        animation.isRemovedOnCompletion = false
        loginButton?.layer.add(animation, forKey: nil)
    }
7.颜色渐变动画
 override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        loginButton?.layer.borderColor = UIColor.gray.cgColor
        loginButton?.layer.cornerRadius = 10.0
        
        // 颜色渐变动画
        let animation: CABasicAnimation = CABasicAnimation()
        animation.keyPath = "backgroundColor"
        animation.duration = 2.0
        animation.fromValue = UIColor.green.cgColor
        animation.toValue = UIColor.red.cgColor
        animation.isRemovedOnCompletion = false
        loginButton?.layer.add(animation, forKey: nil)
    }
  • animation.keyPath = “borderColor” 可设置边框渐变颜色
8.淡入淡出动画
override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        // 淡入淡出动画
        let animation: CABasicAnimation = CABasicAnimation()
        animation.keyPath = "opacity"  // opacity属性默认为0,即隐藏
        animation.duration = 2.0
        animation.fromValue = UIColor.green.cgColor
        animation.toValue = 1.0  // 显示完全
        animation.isRemovedOnCompletion = false
        loginButton?.layer.add(animation, forKey: nil)
    }
9.阴影渐变动画
override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        loginButton?.layer.shadowColor = UIColor.red.cgColor
        loginButton?.layer.shadowOpacity = 0.5  // 半透明

        // 阴影渐变动画
        let animation: CABasicAnimation = CABasicAnimation()
        animation.keyPath = "shadowOffset"
        animation.duration = 2.0
        animation.fromValue = UIColor.green.cgColor
        // 阴影投影角度
        animation.toValue = NSValue(cgSize: CGSize(width: 10, height: 10))
        animation.isRemovedOnCompletion = false
        loginButton?.layer.add(animation, forKey: nil)
    }
CAKeyframeAnimation、CAAnimation Group动画

CAKeyframeAnimation: 是CALayer层下的关键帧动画类,可以实现类似于UIView的关键帧动画效果。CAKeyframeAnimation是CAPropertyAnimation的一个子类,与CABasicAnimation原理类似,都是通过修改CALayer图层的value属性来实现的动画效果。不同的是CABasicAnimation一般只能用fromValue toValue byValue,也就是只能修改一个value值,但是CAKeyframeAnimation可以修改一组value值来实现对动画的精准控制。

1.CAKeyframeAnimation动画属性要点
  • values:数组类型,数组中每个元素都描述一个关键帧动画属性;
  • keyTimers:表示周期,范围0-1;
  • path:设置CGPathRef/CGMutablePathRef绘制路径;
2.CAKeyframeAnimation淡入淡出动画效果
import UIKit

class KeyframeViewController: UIViewController {

    var loginButton: UIButton?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        loginButton = UIButton(frame: CGRect(x: 20, y: 300, width: self.view.frame.width - 40, height: 50))
        loginButton?.backgroundColor = UIColor(red: 50/255.0, green: 185/255.0, blue: 170/255.0, alpha: 1.0)
        loginButton?.setTitle("登录", for: UIControl.State.normal)
        view.addSubview(loginButton!)
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        let animation: CAKeyframeAnimation = CAKeyframeAnimation()
        animation.duration = 10.0
        animation.keyPath = "opacity"
        let valuesArray: [NSNumber] = [NSNumber(value: 0.95),NSNumber(value: 0.85),NSNumber(value: 0.65),NSNumber(value: 0.45),NSNumber(value: 0.00)]
        animation.values = valuesArray
        animation.isRemovedOnCompletion = false
        loginButton?.layer.add(animation, forKey: nil)
    }
}
3.CAKeyframeAnimation任意路径动画
override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        // 可变路径对象
        let pathLine: CGMutablePath = CGMutablePath()
        pathLine.move(to: CGPoint(x: 200, y: 300))
        pathLine.addArc(center: CGPoint(x: 200, y: 200), radius: 50, startAngle: 0, endAngle: CGFloat(Double.pi), clockwise: true)
        
        // 动画
        let animation: CAKeyframeAnimation = CAKeyframeAnimation()
        animation.duration = 3.0
        animation.path = pathLine
        animation.keyPath = "position"
        animation.isRemovedOnCompletion = false
        
        loginButton?.layer.add(animation, forKey: nil)
    }
4.CAAnimation Group组合动画效果
override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        // 可变路径对象
        let pathLine: CGMutablePath = CGMutablePath()
        pathLine.move(to: CGPoint(x: 200, y: 300))
        pathLine.addArc(center: CGPoint(x: 200, y: 200), radius: 50, startAngle: 0, endAngle: CGFloat(Double.pi), clockwise: true)
        
        // 位置动画
        let animation: CAKeyframeAnimation = CAKeyframeAnimation()
        animation.path = pathLine
        animation.keyPath = "position"
        animation.isRemovedOnCompletion = false
        
        // 伸缩动画
        let animationScale: CABasicAnimation = CABasicAnimation()
        animationScale.keyPath = "transform.scale"
        animationScale.toValue = 0.0
        
        // 组合动画
        let animationGroup: CAAnimationGroup = CAAnimationGroup()
        animationGroup.duration = 3.0
        animationGroup.animations = [animation,animationScale]
        animationGroup.isRemovedOnCompletion = false
        
        loginButton?.layer.add(animationGroup, forKey: nil)
    }
实战:水纹按钮动画效果

效果实现:水纹扩散效果:扩散性状是圆形,扩散颜色为粉红色,扩散过程中按钮不可点击;

CAEnitterCell粒子动画效果

CAEmitterLayer为粒子发射图层,用于控制粒子展示范围、发射位置、发射形状、渲染模式等属性。通过CAEmitterCell构建的发射单元都受到CAEmitterLayer图层节制;
CAEmitterCell为粒子发射单元,用于对粒子系统的单个粒子做控制。比如控制粒子的移动速度,方向,范围;
CAEmitterLayer属于CALayer图层,实例化后添加在响应的View上即可。

1.鬼火火焰效果
import UIKit

class EmitterViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        
        self.view.backgroundColor = UIColor.black
        
        // CAEmitterCell
        let emitterCell = CAEmitterCell()
        emitterCell.name = "fire"
        emitterCell.emissionLongitude = CGFloat(Double.pi)
        emitterCell.velocity = 50    // 粒子速度 负数表明向上燃烧
        emitterCell.velocityRange = 50  // 粒子速度范围
        emitterCell.emissionRange = 1.1  // 周围发射速度
        emitterCell.yAcceleration = -200  // 粒子y方向的加速度分量
        emitterCell.scaleSpeed = 0.3   // 缩放比例, 超大火苗
        emitterCell.color = UIColor(red: 0.8, green: 0.4, blue: 0.2, alpha: 0.1).cgColor
        emitterCell.contents = UIImage(named: "fire")?.cgImage
        emitterCell.birthRate = 500  // 粒子生成速度,默认1/秒
        emitterCell.lifetime = 0.5  // 粒子生命周期,默认1秒
        
        // CAEmitterLayer
        let emitterLayer = CAEmitterLayer()
        emitterLayer.position = self.view.center  // 粒子发射位置
        emitterLayer.emitterSize = CGSize(width: 50, height: 10)  // 控制火苗大小
        emitterLayer.renderMode = CAEmitterLayerRenderMode.oldestFirst  // 火苗渲染模式
        emitterLayer.emitterShape = CAEmitterLayerEmitterShape.point  // 发射器形状
        emitterLayer.emitterMode = CAEmitterLayerEmitterMode.points  // 发射模式
//        emitterLayer.seed = 10    // 初始化随机数产生的种子
//        emitterLayer.preservesDepth = true  // 是否开启三维效果
        
        emitterLayer.emitterCells = [emitterCell]
        self.view.layer.addSublayer(emitterLayer)
        
        /*
         
        renderMode:发射器渲染模式
        kCAEmitterLayerUnordered;//粒子无序出现
        kCAEmitterLayerOldestFirst;//声明久的粒子会被渲染在最上层
        kCAEmitterLayerOldestLast;//年轻的粒子会被渲染在最上层
        kCAEmitterLayerBackToFront;//粒子的渲染按照Z轴的前后顺序进行
        kCAEmitterLayerAdditive;//粒子混合
         
         emitterShape:发射器的形状
         kCAEmitterLayerPoint;//点的形状,粒子从一个点发出
         kCAEmitterLayerLine;//线的形状,粒子从一条线发出
         kCAEmitterLayerRectangle;//矩形形状,粒子从一个矩形中发出
         kCAEmitterLayerCuboid;//立方体形状,会影响Z平面的效果
         kCAEmitterLayerCircle;//圆形,粒子会在圆形范围发射
         kCAEmitterLayerSphere;//球型
         
         emitterMode:发射器发射模式
         kCAEmitterLayerPoints;//从发射器中发出
         kCAEmitterLayerOutline;//从发射器边缘发出
         kCAEmitterLayerSurface;//从发射器表面发出
         kCAEmitterLayerVolume;//从发射器中点发出
         
         */
    }
    
}
CAGradientLayer光波扫描动画效果
1.原理

重点:光波的执行方向;光波的颜色梯度;光波的“彗星拖尾”效果;
执行方向:梯度坐标系startPoint和endPoint与当前的frame存在一定的映射关系,例如:从上到下:startPoint为(0,0),endPoint为(0,1), 如果是从左向右:startPoint为(0,0),endPoint为(1,0)
颜色梯度: colors属性是一个颜色数组,第一个参数是底色,第二个参数是光波渐变颜色,第三个参数是原本覆盖在View上的动画颜色;
彗星拖尾:颜色分割属性locations表示颜色渐变所占比例数组;

2.指纹扫描效果
import UIKit

class GradientViewController: UIViewController {

    var imageView: UIImageView?
    
    var rotationIndex: NSInteger = 0
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.black
        // Do any additional setup after loading the view.
        
        imageView = UIImageView.init(frame: CGRect(origin: CGPoint(x: view.bounds.origin.x, y: view.bounds.origin.y), size: CGSize(width: 250, height: 250)))
        imageView?.contentMode = UIView.ContentMode.scaleAspectFill
        imageView?.center = view.center
        imageView?.image = UIImage.init(named: "zhuanpan")
        view.addSubview(imageView!)
        
        // layer图层属性
        let gradientLayer: CAGradientLayer = CAGradientLayer()
        gradientLayer.frame = CGRect(x: 0, y: 0, width: 250, height: 250)
        gradientLayer.startPoint = CGPoint(x: 0, y: 0)
        gradientLayer.endPoint = CGPoint(x: 0, y: 1)
        gradientLayer.colors = [UIColor.clear.cgColor,UIColor.red.cgColor,UIColor.clear.cgColor]
        gradientLayer.locations = [0.0, 0.1, 0.2]
        
        // CABasicAnimation
        let gradientAnimation: CABasicAnimation = CABasicAnimation()
        gradientAnimation.keyPath = "locations"
        gradientAnimation.fromValue = [0.0, 0.1, 0.2]
        gradientAnimation.toValue = [0.8, 0.9, 1.0]
        gradientAnimation.duration = 3.0
        gradientAnimation.repeatCount = 10
        
        gradientLayer.add(gradientAnimation, forKey: nil)
        imageView?.layer.addSublayer(gradientLayer)
    }

}
3.音响音量跳动效果
CAShapeLayer动态图标效果
1.原理

CAShapeLayer可以实现各种图形绘制类动画效果。

2.贝济埃曲线(贝塞尔曲线)

贝济埃曲线依据四个位置任一点的左边绘制的一条光滑曲线。

// View视图
class BizierPathView: UIView {
 
    override func draw(_ rect: CGRect) {
        
        let bezierPath: UIBezierPath = UIBezierPath()
        bezierPath.lineWidth = 4.0
        // 线条端点风格
        bezierPath.lineCapStyle = CGLineCap.round
        // 线段连接处拐角类型
        bezierPath.lineJoinStyle = CGLineJoin.round
        
        // 绘制
        bezierPath.move(to: CGPoint(x: 40, y: 150))
        // 贝塞尔曲线
        bezierPath.addCurve(to: CGPoint(x: 140, y: 200), controlPoint1: CGPoint(x: 20, y: 40), controlPoint2: CGPoint(x: 50, y: 80))
        bezierPath.close()  // 闭合
        
        let strokeColor: UIColor = UIColor(red: 1, green: 0.4, blue: 0.3, alpha: 1.0)
        strokeColor.setStroke()
        let fillColor: UIColor = UIColor(red: 0.23, green: 0.65, blue: 0.66, alpha: 1.0)
        fillColor.setFill()
        
        bezierPath.fill()
        bezierPath.stroke()
    }
}
3.绘制动态图表
1.动态折线动画
2.动态柱状图动画
CAReplicatorLayer图层复制效果
1.原理
2.恒星旋转动画效果
3.音量跳动动画效果

3D动画

3D动画概念
1.锚点的基本概念

AnchorPoint是一个CGPoint类型的值,基于bounds坐标系位置,默认是(0.5,0.5),取值范围是0-1;

2.矩阵变换的基本概念

iOS利用CATransform3D实现3D变换效果,CATransform3D实质是定义了一个三维变换的矩阵;

3.3D旋转效果
Cover Flow 3D效果
1.原理
2.实现

转场动画

CATransition转场动画
1.概念

公有API:(可以使用常量表示: kCATransition)

  • fade:淡入淡出效果
  • push:推送效果
  • reveal:揭开效果
  • movein:移动效果
    私有API:
  • pageCurl:向上翻页效果
  • pageUnCurl:向下翻页效果
  • cube:立方体翻转效果
  • oglFlip:翻转效果
  • stuckEffect:收缩效果
  • rippleEffect:水滴波纹效果
  • cameraIrisHollowOpen:相机打开效果
  • cameraLrisHollowClose:相机关闭效果
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值