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
相关产品推荐
相关产品推荐

