美文网首页CRAnimation布袋的世界之Apple苹果家园小知识点
iOS动画进阶-手摸手教你写ShineButton动画

iOS动画进阶-手摸手教你写ShineButton动画

作者: W_C__L | 来源:发表于2017-03-11 09:43 被阅读136次

    前段时间在github上看见一个非常nice的动画效果,可惜是安卓的,想着用swift写一个iOS版的,下下来源代码研究了一下,下面是我写代码的心路历程

    先上图和demo的地址

    分析动画过程

    刚开始看的时候感觉这个动画很炫酷,实现起来应该挺复制的,后来我将gif图逐一分解,大致浏览了一下安卓的实现过程,大致了解的实现的过程,下面是一些关键的动画步骤:

    1. 第一步是里面图片的缩放动画,使用CALayer配合CAKeyframeAnimation来实现;
    2. 第二步是是里面一个圆环逐渐变大的过程,使用CAShapeLayer配合CAKeyframeAnimation来实现;
    3. 第三步是最外面一层太阳的扩散效果同样也使用CAShapeLayer配合CAKeyframeAnimation来实现;
    4. 最后是闪烁和颜色变化的的效果,使用CABasicAnimationCADisplayLink来实现。

    一、缩放动画的实现

    这个实现的过程相对而言比较简单,用CALayer做为mask来实现下图心形的图片,然后用CAKeyframeAnimation来实现动画,values的值为[0.4, 1, 0.9, 1],差值器模式为kCAAnimationCubic,下面是实现结果和关键代码:

    public func startAnim() {
        let anim = CAKeyframeAnimation(keyPath: "transform.scale")
        anim.duration  = animDuration
        anim.values = [0.4, 1, 0.9, 1]
        anim.calculationMode = kCAAnimationCubic
        maskLayer.add(anim, forKey: "scale")
    }
    

    二、圆环扩散动画的实现

    首先圆环我们用CAShapeLayer来绘制一个圆环,然后通过CAKeyframeAnimation来改变圆环的path就可以了,下面是实现结果和关键代码:

    public func startAnim() {
        let anim = CAKeyframeAnimation(keyPath: "path")
        anim.duration = params.animDuration * 0.1
        let size = frame.size
        let fromPath = UIBezierPath(arcCenter: CGPoint.init(x: size.width/2, y: size.height/2), radius: 1, startAngle: 0, endAngle: CGFloat(M_PI) * 2.0, clockwise: false).cgPath
        let toPath = UIBezierPath(arcCenter: CGPoint.init(x: size.width/2, y: size.height/2), radius: size.width/2 * CGFloat(params.shineDistanceMultiple), startAngle: 0, endAngle: CGFloat(M_PI) * 2.0, clockwise: false).cgPath
        anim.delegate = self
        anim.values = [fromPath, toPath]
        anim.timingFunctions = [CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)]
        anim.isRemovedOnCompletion = false
        anim.fillMode = kCAFillModeForwards
        shapeLayer.add(anim, forKey: "path")
    }
    

    三、太阳的扩散效果实现

    首先我们得先算出每个太阳的位置和将要扩散到的位置,然后用CAShapeLayer绘制出太阳,用CAKeyframeAnimation实现扩散的效果,下面是实现后的结果和关键代码 :

    public func startAnim() {
        let radius = frame.size.width/2 * CGFloat(params.shineDistanceMultiple*1.4)
        var startAngle: CGFloat = 0
        let angle = CGFloat(M_PI*2/Double(params.shineCount)) + startAngle
        if params.shineCount%2 != 0 {
            startAngle = CGFloat(M_PI*2 - (Double(angle)/Double(params.shineCount)))
        }
        for i in 0..<params.shineCount {
            let bigShine = shineLayers[i]
            let bigAnim = getAngleAnim(shine: bigShine, angle: startAngle + CGFloat(angle)*CGFloat(i), radius: radius)
            let smallShine = smallShineLayers[i]
            var radiusSub = frame.size.width*0.15*0.66
            if params.shineSize != 0 {
                radiusSub = params.shineSize*0.66
            }
            let smallAnim = getAngleAnim(shine: smallShine, angle: startAngle + CGFloat(angle)*CGFloat(i) - CGFloat(params.smallShineOffsetAngle)*CGFloat(M_PI)/180, radius: radius-radiusSub)
            bigShine.add(bigAnim, forKey: "path")
            smallShine.add(smallAnim, forKey: "path")
        }
        let angleAnim = CABasicAnimation(keyPath: "transform.rotation")
        angleAnim.duration = params.animDuration * 0.87
        angleAnim.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
        angleAnim.fromValue = 0
        angleAnim.toValue = CGFloat(params.shineTurnAngle)*CGFloat(M_PI)/180
        angleAnim.delegate = self
        add(angleAnim, forKey: "rotate")
    }
    

    四、最后再将这些动画通过一定规律结合起来

    上图是将之前动画步骤组合起来后的效果,上面的一些代码只是部分代码,全部代码可以去我的github地址上去下在浏览,如果大家喜欢可以点一个赞,有更好的想法也可以提出来,大家一起交流一下,最后谢谢大家阅读~~

    相关文章

      网友评论

        本文标题:iOS动画进阶-手摸手教你写ShineButton动画

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