Swift - CAGradientLayer使用详解2(环形渐变进度条、渐变文字)
作者:hangge | 2017-08-31 08:10
在前文中,我简单地介绍了 CAGradientLayer 的使用(点击查看)。当时绘制的都是矩形渐变,其实配合各种 mask(遮罩),我们可以实现多种形状、样式的渐变。

(2)使用样例
源码下载:
hangge_1770.zip

一、渐变圆环进度条
1,效果图
(1)下面实现一个用于温度显示的环形进度条。同一般的环形进度条不同,它的进度轨道是有渐变色的。随着温度的升高(进度值增加),颜色从蓝色慢慢渐变到黄色,最终渐变到红色。
(2)当进度值改变的时候,进度条前进或后退都有动画效果。

2,实现原理
(1)整个进度条组件分成进度条后面的轨道,以及覆盖在上方的具有渐变色的进度条。这里主要讲讲后者的实现。
(2)首先使用 CAShapeLayer 配合 UIBezierPath 绘制一个圆弧,这个便是进度条。进度条长短百分比我们可以通过 CAShapeLayer 的 strokeEnd 属性来实现。
(3)接着我们使用 CAGradientLayer 绘制一个渐变层。由于 CAGradientLayer 不能顺着弧线进行渐变,只能指定两个点之间进行渐变。所以我们先分别绘制左右两部分的渐变:
- 左半部分:颜色从上往下是黄色渐变到蓝色。
- 右半部分:颜色从上往下是黄色渐变到红色。

(4)最后将渐变层的遮罩设置成前面由 CAShapeLayer 创建的进度弧线,这样一个带有渐变色的进度圆弧就完成了。
3,样例代码
(1)TemperatureMeter.swift(进度条组件)
import UIKit
class TemperatureMeter: UIView {
//进度条所在圆的直径
let progressDiameter:CGFloat = 80
//进度条线条宽度
let progressWidth:CGFloat = 4
//进度条轨道颜色
let trackColor = UIColor.lightGray
//渐变进度条
var progressLayer:CAShapeLayer!
//进度文本标签
var label:UILabel!
override init(frame: CGRect) {
super.init(frame: frame)
//创建进度文本标签
label = UILabel(frame:CGRect(x:0, y:0, width:bounds.width,
height:progressDiameter))
label.textAlignment = .center
label.text = "0℃"
self.addSubview(label)
//轨道以及上面进度条的路径(在组件内部水平居中)
let path = UIBezierPath(arcCenter: CGPoint(x: bounds.midX, y: 40),
radius: (progressDiameter-progressWidth)/2,
startAngle: toRadians(degrees: -210),
endAngle: toRadians(degrees: 30),
clockwise: true)
//绘制进度条背景轨道
let trackLayer = CAShapeLayer()
trackLayer.frame = self.bounds
trackLayer.fillColor = UIColor.clear.cgColor
//设置轨道颜色
trackLayer.strokeColor = trackColor.cgColor
//设置轨道透明度
trackLayer.opacity = 0.25
//轨道使用圆角线条
trackLayer.lineCap = kCALineCapRound
//轨道线条的宽度
trackLayer.lineWidth = progressWidth
//设置轨道路径
trackLayer.path = path.cgPath
//将轨道添加到视图层中
self.layer.addSublayer(trackLayer)
//绘制进度条
progressLayer = CAShapeLayer()
progressLayer.frame = self.bounds
progressLayer.fillColor = UIColor.clear.cgColor
progressLayer.strokeColor = UIColor.black.cgColor
progressLayer.lineCap = kCALineCapRound
progressLayer.lineWidth = progressWidth
progressLayer.path = path.cgPath
//进度条默认结束位置是0
progressLayer.strokeEnd = 0
//将进度条添加到视图层中
self.layer.addSublayer(progressLayer)
//绘制左侧的渐变层(从上往下是:由黄变蓝)
let gradientLayer1 = CAGradientLayer()
gradientLayer1.frame = CGRect(x:0, y:0, width:self.frame.width/2,
height:progressDiameter/4 * 3 + progressWidth)
gradientLayer1.colors = [UIColor.yellow.cgColor,
UIColor.green.cgColor,
UIColor.cyan.cgColor,
UIColor.blue.cgColor]
gradientLayer1.locations = [0.1,0.4,0.6,1]
//绘制右侧的渐变层(从上往下是:由黄变红)
let gradientLayer2 = CAGradientLayer()
gradientLayer2.frame = CGRect(x:self.frame.width/2, y:0, width:self.frame.width/2,
height:progressDiameter/4 * 3 + progressWidth)
gradientLayer2.colors = [UIColor.yellow.cgColor,
UIColor.red.cgColor]
gradientLayer2.locations = [0.1,0.8]
//用于存放左右两侧的渐变层,并统一添加到视图层中
let gradientLayer = CALayer()
gradientLayer.addSublayer(gradientLayer1)
gradientLayer.addSublayer(gradientLayer2)
self.layer.addSublayer(gradientLayer)
//将渐变层的遮罩设置为进度条
gradientLayer.mask = progressLayer
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//设置进度(可以设置是否播放动画,以及动画时间)
func setPercent(percent:CGFloat, animated:Bool = true) {
//改变进度条终点,并带有动画效果(如果需要的话)
CATransaction.begin()
CATransaction.setDisableActions(!animated)
CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name:
kCAMediaTimingFunctionEaseInEaseOut))
progressLayer.strokeEnd = percent/100.0
CATransaction.commit()
//设置文本标签值
label.text = "\(Int(percent))℃"
}
//把角度转换成弧度
func toRadians(degrees:CGFloat) -> CGFloat {
return .pi*(degrees)/180.0
}
}
(2)使用样例
import UIKit
class ViewController: UIViewController {
//滑块组件
@IBOutlet weak var slider: UISlider!
//温度计组件
var meter:TemperatureMeter!
override func viewDidLoad() {
super.viewDidLoad()
//创建并添加温度计组件
meter = TemperatureMeter(frame: CGRect(x: 40, y: 80, width: 80, height: 80))
self.view.addSubview(meter)
}
//滑块值改变响应
@IBAction func sliderDidchange(_ sender: Any) {
//设置进度
meter.setPercent(percent: CGFloat(slider.value))
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
源码下载:
二、渐变文字
1,效果图
“hangge.com”这个标签文字使用的是渐变色,从上往下由黄色渐变到橙色。

2,实现原理
(1)首先分别创建渐变层和文本标签。
(2)接着将渐变层的 mask 设置为文本标签即可。
3,样例代码
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//创建用于放置文本标签和渐变层的view
let container = UIView(frame:CGRect(x:10, y:40, width:300, height:70))
self.view.addSubview(container)
//创建文本标签
let label = UILabel(frame:CGRect(x:0, y:0, width:300, height:70))
label.text = "hangge.com"
label.font = UIFont.boldSystemFont(ofSize: 52.0)
container.addSubview(label)
//创建渐变层
//定义渐变的颜色(从黄色渐变到橙色)
let topColor = UIColor(red: 0xfe/255, green: 0xd3/255, blue: 0x2f/255, alpha: 1)
let buttomColor = UIColor(red: 0xfc/255, green: 0x68/255, blue: 0x20/255, alpha: 1)
let gradientColors = [topColor.cgColor, buttomColor.cgColor]
//定义每种颜色所在的位置
let gradientLocations:[NSNumber] = [0.0, 1.0]
//创建CAGradientLayer对象并设置参数
let gradientLayer = CAGradientLayer()
gradientLayer.colors = gradientColors
gradientLayer.locations = gradientLocations
//设置其CAGradientLayer对象的frame,并插入container的layer
gradientLayer.frame = label.frame
container.layer.insertSublayer(gradientLayer, at: 0)
//将渐变层的遮罩设置为label
gradientLayer.mask = label.layer
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
全部评论(3)
太感谢了,支持!
站长回复:多谢支持
加油加油
站长回复:谢谢你的支持和鼓励,我会继续更新下去的,欢迎常来看看。
默默支持,希望一直坚持下去
站长回复:谢谢你的支持,我会坚持下去的。