Swift - CAGradientLayer渐变动画的实现3(彩虹动画进度条)
本文接着演示如何实现一个自定义的彩虹进度条,其动画原理和上一篇介绍的彩虹动画圆环其实是差不多的。
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()
}
}
源码下载:

航哥,什么时候出几个RxSwift的demo