返回 导航

Swift

hangge.com

Swift - CAGradientLayer渐变动画的实现3(彩虹动画进度条)

作者:hangge | 2017-09-14 08:10
本文接着演示如何实现一个自定义的彩虹进度条,其动画原理和上一篇介绍的彩虹动画圆环其实是差不多的。

1,效果图

(1)整个进度条显示的是彩虹色的渐变。而且彩虹条不是固定不动的,会从左往右无限循环轮播移动。
(2)拖动滑块可以调整进度条的进度。
(3)点击下方开关可以停止、或者启用彩虹条移动的动画效果。 
           

2,实现方式

(1)使用 CAGradientLayer 创建一个从左至右的彩虹色渐变,然后使用 CAShapeLayer 配合 UIBezierPath 绘制一条横线作为它的遮罩,便实现了一个彩虹色的进度条。
(2)进度条长短百分比我们可以通过 CAShapeLayer strokeEnd 属性来实现。
(3)动画部分同样使用 CABasicAnimation 实现,将渐变色数组中的最后一个颜色元素移到第一个位置,这样动画播放时看起来就像是渐变层从左往右移动。
(4)最后在动画结束方法中再重复执行上面的动作,便实现了无限循环轮播移动的动画。

3,样例代码

(1)彩虹进度条组件(RainbowProgress.swift
import UIKit

class RainbowProgress: UIView, CAAnimationDelegate {
    
    //当前正在播放动画
    var isAnimating = false
    
    //渐变层
    var gradientLayer: CAGradientLayer!
    
    //遮罩层
    var maskLayer:CAShapeLayer!
    
    //初始化方法
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        //创建彩虹渐变层
        gradientLayer =  CAGradientLayer()
        gradientLayer.startPoint = CGPoint(x:0, y:0)
        gradientLayer.endPoint = CGPoint(x:1, y:0)
        gradientLayer.frame = self.frame
        
        //设置渐变层的颜色
        var rainBowColors:[CGColor] = []
        var hue:CGFloat = 0
        while hue <= 360 {
            let color = UIColor(hue: 1.0*hue/360.0, saturation: 1.0, brightness: 1.0,
                                alpha: 1.0)
            rainBowColors.append(color.cgColor)
            hue += 5
        }
        gradientLayer.colors = rainBowColors
        
        //添加渐变层
        self.layer.addSublayer(gradientLayer)
        
        //创建遮罩层(使用贝塞尔曲线绘制)
        let shapePath = UIBezierPath()
        shapePath.move(to: CGPoint(x:0, y:0))
        shapePath.addLine(to: CGPoint(x:self.bounds.size.width, y:0))
        
        maskLayer = CAShapeLayer()
        maskLayer.path = shapePath.cgPath
        maskLayer.lineWidth = self.frame.height
        maskLayer.fillColor = UIColor.clear.cgColor
        maskLayer.strokeColor = UIColor.black.cgColor
        //遮罩层的起始、终止位置均为0
        maskLayer.strokeStart = 0
        maskLayer.strokeEnd = 0
        
        //设置遮罩
        gradientLayer.mask = maskLayer
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    //执行动画
    func performAnimation(){
        //更新渐变层的颜色
        let fromColors = gradientLayer.colors as! [CGColor]
        let toColors = self.shiftColors(colors: fromColors)
        gradientLayer.colors = toColors
        //创建动画实现渐变颜色从左向右移动的效果
        let animation = CABasicAnimation(keyPath: "colors")
        animation.fromValue = fromColors
        animation.toValue = toColors
        animation.duration = 0.08
        //动画完成后是否要移除
        animation.isRemovedOnCompletion = true
        animation.fillMode = kCAFillModeForwards
        animation.timingFunction = CAMediaTimingFunction(name:
            kCAMediaTimingFunctionLinear)
        animation.delegate = self
        //将动画添加到图层中
        layer.add(animation, forKey: "animateGradient")
    }
    
    //动画播放结束后的响应
    func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
        //根据isAnimating属性判断是否还有继续播放动画
        if isAnimating {
            self.performAnimation()
        }
    }
    
    //将颜色数组中的最后一个元素移到数组的最前面
    func shiftColors(colors:[CGColor]) -> [CGColor] {
        //复制一个数组
        var newColors: [CGColor] = colors.map{($0.copy()!) }
        //获取最后一个元素
        let last: CGColor = newColors.last!
        //将最后一个元素删除
        newColors.removeLast()
        //将最后一个元素插入到头部
        newColors.insert(last, at: 0)
        //返回新的颜色数组
        return newColors
    }
    
    //开始播放动画
    func startAnimating() {
        if !isAnimating {
            self.isAnimating = true
            self.performAnimation()
        }
    }
    
    //停止播放动画
    func stopAnimating(){
        if isAnimating {
            self.isAnimating = false
        }
    }
    
    //当前进度
    var _progressValue:CGFloat = 0
    var progressValue:CGFloat {
        get{
            return _progressValue
        }
        set{
            _progressValue = newValue > 1 ? 1 : newValue
            _progressValue = newValue < 0 ? 0 : newValue
            self.maskLayer.strokeEnd = _progressValue
        }
    }
}


(2)主视图控制器(ViewController.swift
import UIKit

class ViewController: UIViewController {
    
    //滑块组件
    @IBOutlet weak var slider: UISlider!
    
    //开关组件
    @IBOutlet weak var uiSwitch: UISwitch!
    
    //彩虹进度条组件
    var rainbowProgress:RainbowProgress!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //创建彩虹进度条
        let frame = CGRect(x:0, y:50, width:self.view.frame.width, height:4)
        rainbowProgress = RainbowProgress(frame: frame)

        //开始播放彩虹动画
        rainbowProgress.startAnimating()
    
        //将彩虹进度条添加到界面上
        self.view.addSubview(rainbowProgress)
    }
    
    //滑块值改变响应
    @IBAction func sliderDidchange(_ sender: Any) {
        //设置进度
        self.rainbowProgress.progressValue = CGFloat(slider.value)
    }
    
    //开关值改变响应
    @IBAction func switchDidChange(_ sender: Any) {
        if uiSwitch.isOn {
            //开始播放彩虹动画
            rainbowProgress.startAnimating()
        }else{
            //停止播放彩虹动画
            rainbowProgress.stopAnimating()
        }
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

源码下载hangge_1773.zip
评论

全部评论(1)

回到顶部