美文网首页
iOS 动画——让你的APP动起来

iOS 动画——让你的APP动起来

作者: Jt_Self | 来源:发表于2017-08-31 10:25 被阅读0次
    这篇文章汇总了几种我在学习与工作中遇到的几种动画,在此记录一下以便自己以后复习,同时也希望与大家交流学习。

Talk is cheap, Show me the code.

1、画线动画及沿路径移动
self.view.backgroundColor = UIColor.init(red: 44/255.0, green: 34/255.0, blue: 85/255.0, alpha: 1)
        let bezierPath = UIBezierPath()
        bezierPath.move(to: CGPoint(x: 50, y: 100))
        bezierPath.addLine(to: CGPoint(x: 325, y: 100))
        bezierPath.addLine(to: CGPoint(x: 80, y: 250))
        bezierPath.addLine(to: CGPoint(x: 275, y: 250))
        bezierPath.addLine(to: CGPoint(x: self.view.frame.width/2.0, y: 220))
        bezierPath.addLine(to: CGPoint(x: self.view.frame.width/2.0, y: 400))
        bezierPath.addLine(to: CGPoint(x: 30, y: 400))
        bezierPath.addLine(to: CGPoint(x: 345, y: 400))
        
        //画线
        let shapeLayer = CAShapeLayer()
        shapeLayer.strokeColor = UIColor.purple.cgColor
        shapeLayer.fillColor = UIColor.clear.cgColor
        shapeLayer.lineWidth = 2
        shapeLayer.lineJoin = kCALineJoinRound
        shapeLayer.lineCap = kCALineCapRound
        shapeLayer.path = bezierPath.cgPath
        view.layer.addSublayer(shapeLayer)
        
        let pathAnim = CABasicAnimation(keyPath: "strokeEnd")
        pathAnim.duration = 5.0
        pathAnim.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
        pathAnim.fromValue = 0//开始
        pathAnim.toValue = 1//到100%
        pathAnim.autoreverses = true// 动画按原路径返回
        pathAnim.fillMode = kCAFillModeForwards
        //        pathAnim.isRemovedOnCompletion = false
        pathAnim.repeatCount = Float.infinity
        shapeLayer.add(pathAnim, forKey: "strokeEndAnim")
        
        
        //视图沿路径移动
        let moveV = UIImageView.init(image: UIImage.init(named: ""))
        moveV.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
        moveV.backgroundColor = UIColor.red
        moveV.center = CGPoint(x: 50, y: 100)
        view.addSubview(moveV)
        
        let keyAnima = CAKeyframeAnimation.init(keyPath: "position")
//        keyAnima.delegate = self
        keyAnima.duration = 5.0
        keyAnima.timingFunction = CAMediaTimingFunction.init(name: kCAMediaTimingFunctionEaseInEaseOut)
        keyAnima.path = bezierPath.cgPath
        keyAnima.fillMode = kCAFillModeForwards//动画开始之后layer的状态将保持在动画的最后一帧,而removedOnCompletion的默认属性值是 YES,所以为了使动画结束之后layer保持结束状态,应将removedOnCompletion设置为NO
        keyAnima.isRemovedOnCompletion = false
        moveV.layer.add(keyAnima, forKey: "moveAnimation")
2、水面波浪
 lazy var waveDisplaylink = CADisplayLink()
    
    lazy var firstWaveLayer = CAShapeLayer()
    
    lazy var secondWaveLayer = CAShapeLayer()
    
    var firstWaveColor: UIColor?
    
    /// 水纹振幅
    var waveA: CGFloat = 10
    
    /// 水纹周期
    var waveW: CGFloat = 1/30.0;
    
    /// 位移
    var offsetX: CGFloat = 0
    
    /// 当前波浪高度Y
    var currentK: CGFloat = 0
    
    /// 水纹速度
    var waveSpeed: CGFloat = 0
    
    /// 水纹路宽度
    var waterWaveWidth: CGFloat = 0
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = UIColor.init(red: 44/255.0, green: 34/255.0, blue: 85/255.0, alpha: 1)
        self.view.layer.masksToBounds = true
        
        
        setUpUI()
        
    }
    
    
    func setUpUI () {
        
        // 波浪宽
        waterWaveWidth = self.view.bounds.size.width
        // 波浪颜色
        firstWaveColor = UIColor.green
        // 波浪速度
        waveSpeed = 0.4 / CGFloat(M_PI)
        // 设置闭环的颜色
        firstWaveLayer.fillColor = UIColor.init(colorLiteralRed: 73/255.0, green: 142/255.0, blue: 178/255.0, alpha: 0.5).cgColor
        // 设置边缘线的颜色
        //        firstWaveLayer.strokeColor = UIColor.blue.cgColor
        firstWaveLayer.strokeStart = 0.0
        firstWaveLayer.strokeEnd = 0.8
        // 设置闭环的颜色
        secondWaveLayer.fillColor = UIColor.init(colorLiteralRed: 73/255.0, green: 142/255.0, blue: 178/255.0, alpha: 0.5).cgColor
        // 设置边缘线的颜色
        //        secondWaveLayer.strokeColor = UIColor.blue.cgColor
        secondWaveLayer.strokeStart = 0.0
        secondWaveLayer.strokeEnd = 0.8
        self.view.layer.addSublayer(firstWaveLayer)
        self.view.layer.addSublayer(secondWaveLayer)
        
        // 设置波浪流动速度
        waveSpeed = 0.05
        // 设置振幅
        waveA = 8
        // 设置周期
        waveW = 2 * CGFloat(M_PI) / self.view.bounds.size.width
        // 设置波浪纵向位置
        currentK = self.view.bounds.size.height / 2 //屏幕居中
        
        waveDisplaylink = CADisplayLink(target: self, selector: #selector(getCurrentWave))
        waveDisplaylink.add(to: RunLoop.current, forMode: .commonModes)
        
    }
    
    
    @objc private func getCurrentWave(disPlayLink: CADisplayLink) {
        // 实时位移
        offsetX += waveSpeed
        setCurrentFirstWaveLayerPath()
    }
    
    private func setCurrentFirstWaveLayerPath() {
        // 创建一个路径
        let path = CGMutablePath()
        var y = currentK
        path.move(to: CGPoint(x: 0, y: y))
        
        for i in 0...Int(waterWaveWidth) {
            y = waveA * sin(waveW * CGFloat(i) + offsetX) + currentK
            path.addLine(to: CGPoint(x: CGFloat(i), y: y))
        }
        
        path.addLine(to: CGPoint(x: waterWaveWidth, y: self.view.bounds.size.height))
        path.addLine(to: CGPoint(x: 0, y: self.view.bounds.size.height))
        path.closeSubpath()
        firstWaveLayer.path = path
        
        // 创建一个路径
        let path2 = CGMutablePath()
        var y2 = currentK
        path2.move(to: CGPoint(x: 0, y: y))
        
        for i in 0...Int(waterWaveWidth) {
            y2 = waveA * sin(waveW * CGFloat(i) + offsetX - waterWaveWidth/2 ) + currentK
            path2.addLine(to: CGPoint(x: CGFloat(i), y: y2))
        }
        
        path2.addLine(to: CGPoint(x: waterWaveWidth, y: self.view.bounds.size.height))
        path2.addLine(to: CGPoint(x: 0, y: self.view.bounds.size.height))
        path2.closeSubpath()
        secondWaveLayer.path = path2
    }
3、雪花飘落动画
func snowAnimation() {
        
        //粒子发射器
        let snowEmitter = CAEmitterLayer()
        //粒子发射的位置
        snowEmitter.emitterPosition = CGPoint(x: 100, y: 30)
        //发射源的大小
        snowEmitter.emitterSize = CGSize(width: self.view.bounds.size.width, height: 0)
        //发射模式
        snowEmitter.emitterMode = kCAEmitterLayerOutline
        //发射源的形状
        snowEmitter.emitterShape = kCAEmitterLayerLine
                
        //创建雪花粒子
        let cell = CAEmitterCell()
        //粒子的名称
        cell.name = "snow"
        //粒子参数的速度乘数因子。越大出现的越快
        cell.birthRate = 1.0
        //存活时间
        cell.lifetime = 120.0
        //粒子速度
        cell.velocity = -10
        //粒子速度范围
        cell.velocityRange = 10
        //粒子y方向的加速度分量
        cell.yAcceleration = 3
        //周围发射角度
        cell.emissionRange = CGFloat(0.5 * M_PI)
        //粒子旋转角度范围
        cell.spinRange = CGFloat(0.25 * Double.pi)
        //粒子图片
        cell.contents = UIImage.init(named: "snow")?.cgImage
        //粒子颜色
        cell.color = UIColor.white.cgColor
        
        //设置阴影
        snowEmitter.shadowOpacity = 1.0
        snowEmitter.shadowRadius = 0.0
        snowEmitter.shadowOffset = CGSize(width: 0.0, height: 1.0)
        snowEmitter.shadowColor = UIColor.white.cgColor
            
        // 将粒子添加到粒子发射器上
        snowEmitter.emitterCells = [cell]
        
        self.view.layer .addSublayer(snowEmitter)
    }
4、烟花动画
/// 烟花粒子动画
    func fireworksAnimation() {
        
        //分为3种粒子,子弹粒子,爆炸粒子,散开粒子
        let fireworkEmitter = CAEmitterLayer()
        fireworkEmitter.emitterPosition = CGPoint(x: self.view.bounds.size.width/2.0, y: self.view.bounds.size.height)
        fireworkEmitter.emitterSize = CGSize(width: self.view.bounds.size.width/2.0, height: 0.0)
        fireworkEmitter.emitterMode = kCAEmitterLayerOutline
        fireworkEmitter.emitterShape = kCAEmitterLayerLine
        fireworkEmitter.renderMode = kCAEmitterLayerAdditive
        fireworkEmitter.seed = (arc4random()%100)+1
        
        // Create the rocket
        let rocket = CAEmitterCell()
        
        rocket.birthRate = 1.0
        rocket.velocity = 380
        rocket.velocityRange = 100
        rocket.yAcceleration = 75
        rocket.lifetime = 1.02
        
        //小圆球图片
        rocket.contents         = UIImage.init(named: "dot")?.cgImage
        rocket.scale            = 0.2;
        rocket.color            = UIColor.yellow.cgColor
        rocket.greenRange       = 1.0;      // different colors
        rocket.redRange         = 1.0;
        rocket.blueRange        = 1.0;
        rocket.spinRange        = CGFloat(M_PI);        // slow spin
        
        // the burst object cannot be seen, but will spawn the sparks
        // we change the color here, since the sparks inherit its value
        let burst = CAEmitterCell()
        
        burst.birthRate         = 1.0;      // at the end of travel
        burst.velocity          = 0;        //速度为0
        burst.scale             = 2.5;      //大小
        burst.redSpeed = -1.5// shifting
        burst.blueSpeed = +1.5
        burst.greenSpeed = +1.0
        burst.lifetime          = 0.35;     //存在时间
        
        // and finally, the sparks
        let spark = CAEmitterCell()
        
        spark.birthRate         = 400;
        spark.velocity          = 125;
        spark.emissionRange     = CGFloat(2 * M_PI);    // 360 度
        spark.yAcceleration     = 75;       // gravity
        spark.lifetime          = 3;
        //星星图片
        spark.contents          = UIImage.init(named: "star")?.cgImage
        spark.scaleSpeed        = -0.2;
        spark.greenSpeed = -0.1;
        spark.redSpeed = 0.4;
        spark.blueSpeed = -0.1;
        spark.alphaSpeed = -0.25;
        spark.spin = CGFloat(2 * M_PI)
        spark.spinRange = CGFloat(2 * M_PI)
        
        // 3种粒子组合,可以根据顺序,依次烟花弹-烟花弹粒子爆炸-爆炸散开粒子
        fireworkEmitter.emitterCells    = [rocket];
        rocket.emitterCells             = [burst];
        burst.emitterCells              = [spark];
        self.view.layer.addSublayer(fireworkEmitter)
    }

5、火苗效果
/// 火焰效果
    func fireAnimation() {
        
        // 发射器在xy平面的中心位置
        fireEmitter.emitterPosition = view.center
        // 发射器的尺寸大小
        //        fireEmitter.emitterSize = CGSize(width: 20, height: 60)
        // 发射器的发射模式
        //        fireEmitter.emitterMode = kCAEmitterLayerOutline
        //        // 发射器的形状
        fireEmitter.emitterShape = kCAEmitterLayerCircle
        // 发射器渲染模式
        fireEmitter.renderMode = kCAEmitterLayerAdditive
        
        // 发射单元 - 火焰
        let fire = CAEmitterCell()
        // 粒子的创建速率,默认为1/s。
        fire.birthRate = 200
        // 粒子存活时间
        fire.lifetime = 0.2
        // 粒子的生存时间容差
        fire.lifetimeRange = 0.5
        fire.color = UIColor.init(colorLiteralRed: 0.8, green: 0.4, blue: 0.2, alpha: 0.1) .cgColor
        fire.contents = UIImage(named: "fire.png")?.cgImage
        fire.name = "fire"
        // 粒子的速度
        fire.velocity = 35
        // 粒子动画的速度容差
        fire.velocityRange = 10
        // 粒子在xy平面的发射角度
        fire.emissionLongitude = CGFloat(M_PI + M_PI_2)
        // 粒子发射角度的容差
        fire.emissionRange = CGFloat(M_PI_2)
        // 缩放速度
        fire.scaleSpeed = 0.3
        // 旋转度
        //        fire.spin = 0.2
        
        fireEmitter.emitterCells = [fire]
        view.layer.addSublayer(fireEmitter)
    }
6、流星动画
var timer : Timer!
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        
        
        timer.invalidate()
        timer = nil
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = UIColor.init(red: 44/255.0, green: 34/255.0, blue: 85/255.0, alpha: 1)

        // Do any additional setup after loading the view.
        timer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(liuXingAnimation), userInfo: nil, repeats: true)
    }
    
    ///流星动画
    func liuXingAnimation() {
        let rect    = CGRect(x: self.view.bounds.size.width, y: self.view.bounds.height, width: 100, height: 100)
        let emitter = CAEmitterLayer()
        emitter.frame = rect
        self.view.layer.addSublayer(emitter)
        emitter.renderMode   = kCAEmitterLayerAdditive//合并粒子重叠部分的亮度使得看上去更亮
        emitter.emitterPosition     = CGPoint(x: rect.width/2, y:rect.height/2)
        let            cell  = CAEmitterCell()
        let           image  = UIImage(named: "liuxing")!
        cell.contents        = image.cgImage
        cell.birthRate       = 500 //每秒产生150个粒子
        cell.lifetime        = 5.0
        cell.color           = UIColor.init(red: 1, green: 1, blue: 1, alpha: 0.5).cgColor
        
        cell.alphaSpeed      = -0.6//粒子的透明度每过一秒就减少0.4
        
        cell.velocity        = 50
        cell.velocityRange   = 20   //初始速度值变化的范围 30 ~ 70
        cell.emissionLongitude = CGFloat(-Double.pi/2/180*45)//向上(x-y平面的发射方向)
        cell.emissionRange   = CGFloat(Double.pi/2/180)//围绕发射方向的弧度数
        cell.scale           = 0.2
        emitter.emitterCells = [cell]
        self.view.layer.addSublayer(emitter)
        
        let aPath = UIBezierPath()
        let height : UInt32 = UInt32(self.view.bounds.height-50)
        let randomY = CGFloat(arc4random()%height)
        
        aPath.move(to: CGPoint(x: self.view.bounds.width, y: randomY))
        aPath.addLine(to: CGPoint(x: -100, y: self.view.bounds.width/2+randomY))
        
        let animation = CAKeyframeAnimation(keyPath: "position")
        animation.duration = 5;
        animation.timingFunction = CAMediaTimingFunction.init(name: kCAMediaTimingFunctionEaseIn)
        animation.repeatCount = 1
        animation.path = aPath.cgPath
        //        animation.calculationMode = kCAAnimationPaced
        animation.setValue("liuxing", forKey: "liuxing")
        //                animation.rotationMode = kCAAnimationRotateAutocell
        emitter.add(animation, forKey: "moveTheSquare")
//        animation.delegate = self
    }

7、Lottie加载动画

使用这个动画需要在项目中加入Lottie三方库,我在项目中使用了cocoapod。只需要在其中加入 pod 'lottie-ios' 即可。 其中的动画使用AE制作生成的 json 文件。 你也可以去这里下载你喜欢的动效。

animationArr = ["LottieLogo1_masked", "9squares-AlBoardman", "HamburgerArrow", "IconTransitions", "LottieLogo1", "LottieLogo2", "MotionCorpse-Jrcanest", "PinJump"];
        
        let temp = Int(arc4random()%(UInt32(animationArr.count)))
        animationStr = animationArr[temp]
        
        contentView.layer.masksToBounds = true
        animationView = LOTAnimationView(name: animationStr)
        animationView.frame = self.contentView.bounds
        animationView.contentMode = .scaleAspectFill
        self.contentView.addSubview(animationView)
        animationView.play{ (finished) in
            // Do Something
        }

8、后续待更新...

9、后记

如果大家对这些效果有兴趣,可以去github下载源码,若对您有帮助的话,请多多star哦!

相关文章

网友评论

      本文标题:iOS 动画——让你的APP动起来

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