返回 导航

Swift

hangge.com

Swift - CAGradientLayer使用详解2(环形渐变进度条、渐变文字)

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

一、渐变圆环进度条

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()
    }
}

源码下载hangge_1770.zip

二、渐变文字

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()

    }
}
评论

全部评论(2)

回到顶部