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)
航哥,什么时候出几个RxSwift的demo
站长回复:好的,后面会考虑的。