You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS中带渐隐效果的圆角头部环形进度条实现咨询

实现带圆角头部+路径淡入淡出的环形进度条

要实现你需要的环形进度条效果,我们可以基于UIKit的CAShapeLayer结合渐变蒙版来完成,核心是三个要点:设置进度环的圆角头部、绘制基础环形背景、给进度环添加沿路径的淡入淡出渐变蒙版。下面是完整的Swift实现方案:

自定义进度条View实现

创建FadeCircularProgressView继承自UIView,封装所有图层逻辑:

import UIKit

class FadeCircularProgressView: UIView {
    // 背景环图层
    private let backgroundLayer = CAShapeLayer()
    // 进度环图层
    private let progressLayer = CAShapeLayer()
    // 渐变蒙版:实现进度的淡入淡出
    private let gradientMaskLayer = CAGradientLayer()
    
    // 进度值(范围0-1)
    var progress: CGFloat = 0 {
        didSet {
            updateProgress()
        }
    }
    
    // 环形线条宽度
    var lineWidth: CGFloat = 10 {
        didSet {
            setupLayers()
        }
    }
    
    // 进度环颜色
    var progressColor: UIColor = .systemBlue {
        didSet {
            progressLayer.strokeColor = progressColor.cgColor
        }
    }
    
    // 背景环颜色
    var backgroundRingColor: UIColor = .systemGray5 {
        didSet {
            backgroundLayer.strokeColor = backgroundRingColor.cgColor
        }
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupLayers()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupLayers()
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        setupLayers()
    }
}

private extension FadeCircularProgressView {
    func setupLayers() {
        // 清除旧图层,避免重复添加
        backgroundLayer.removeFromSuperlayer()
        progressLayer.removeFromSuperlayer()
        gradientMaskLayer.removeFromSuperlayer()
        
        // 绘制环形路径:以View中心为圆心,半径减去线条宽度的一半,起始角度从顶部开始
        let center = CGPoint(x: bounds.midX, y: bounds.midY)
        let radius = min(bounds.width, bounds.height) / 2 - lineWidth / 2
        let circularPath = UIBezierPath(arcCenter: center,
                                        radius: radius,
                                        startAngle: -CGFloat.pi / 2,
                                        endAngle: 3 * CGFloat.pi / 2,
                                        clockwise: true)
        
        // 配置背景环
        backgroundLayer.path = circularPath.cgPath
        backgroundLayer.strokeColor = backgroundRingColor.cgColor
        backgroundLayer.fillColor = UIColor.clear.cgColor
        backgroundLayer.lineWidth = lineWidth
        backgroundLayer.strokeEnd = 1.0
        layer.addSublayer(backgroundLayer)
        
        // 配置进度环:关键设置lineCap为.round实现圆角头部
        progressLayer.path = circularPath.cgPath
        progressLayer.strokeColor = progressColor.cgColor
        progressLayer.fillColor = UIColor.clear.cgColor
        progressLayer.lineWidth = lineWidth
        progressLayer.strokeEnd = 0.0
        progressLayer.lineCap = .round
        layer.addSublayer(progressLayer)
        
        // 配置渐变蒙版:实现沿进度路径的淡入淡出
        gradientMaskLayer.frame = bounds
        // 渐变颜色:透明 → 不透明 → 透明,对应进度两端的淡入淡出
        gradientMaskLayer.colors = [UIColor.clear.cgColor,
                                    UIColor.white.cgColor,
                                    UIColor.clear.cgColor]
        // 渐变位置:调整这里的数值可以控制淡入淡出的范围
        gradientMaskLayer.locations = [0.0, 0.1, 0.9, 1.0]
        gradientMaskLayer.startPoint = CGPoint(x: 0, y: 0.5)
        gradientMaskLayer.endPoint = CGPoint(x: 1, y: 0.5)
        
        // 将蒙版绑定到进度环
        progressLayer.mask = gradientMaskLayer
    }
    
    func updateProgress() {
        // 限制进度值在0-1区间内
        let clampedProgress = max(0, min(progress, 1))
        
        // 根据进度调整蒙版位置,避免进度较小时淡入淡出效果异常
        if clampedProgress <= 0.1 {
            gradientMaskLayer.locations = [0.0, clampedProgress, clampedProgress, 1.0]
        } else if clampedProgress >= 0.9 {
            gradientMaskLayer.locations = [0.0, 0.1, clampedProgress, 1.0]
        } else {
            gradientMaskLayer.locations = [0.0, 0.1, 0.9, 1.0]
        }
        
        // 带动画更新进度
        CATransaction.begin()
        CATransaction.setAnimationDuration(0.3)
        progressLayer.strokeEnd = clampedProgress
        CATransaction.commit()
    }
}

使用示例

在ViewController中直接实例化并使用这个自定义View:

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        
        let progressView = FadeCircularProgressView(frame: CGRect(x: 0, y: 0, width: 220, height: 220))
        progressView.center = view.center
        progressView.lineWidth = 18
        progressView.progressColor = .systemTeal
        progressView.backgroundRingColor = .systemGray6
        view.addSubview(progressView)
        
        // 模拟进度变化
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            progressView.progress = 0.7
        }
    }
}

关键细节说明

  • 圆角头部:通过设置progressLayer.lineCap = .round实现进度环两端的圆角效果。
  • 淡入淡出效果:利用CAGradientLayer作为进度环的蒙版,通过调整渐变的颜色和位置,让进度环的两端呈现透明到不透明的过渡。
  • 进度适配:在updateProgress方法中根据当前进度调整蒙版的位置,避免进度较小时淡入淡出范围超出实际进度长度。

内容的提问来源于stack exchange,提问作者Addev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 05:40:56