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

如何用Swift实现带多色单圆环、端点圆角的环形UIProgressView

Swift 环形边框样式进度条实现方案

核心实现逻辑

要实现带圆角端点的环形进度条,核心是利用系统自带的描边端点配置,无需手动绘制圆角,实现成本极低。

1. SwiftUI 实现(适配 iOS 15+)

直接通过Circle的描边属性控制即可,示例代码如下:

struct CircularProgressView: View {
    // 进度值 取值范围0~1
    @Binding var progress: CGFloat
    // 环宽度
    let lineWidth: CGFloat = 16
    // 背景轨道环颜色
    let trackColor: Color = .gray.opacity(0.2)
    // 进度环颜色
    let progressColor: Color = .blue
    
    var body: some View {
        ZStack {
            // 背景轨道环
            Circle()
                .stroke(trackColor, lineWidth: lineWidth)
            // 进度环
            Circle()
                .trim(from: 0, to: progress)
                .stroke(progressColor, style: StrokeStyle(
                    lineWidth: lineWidth,
                    lineCap: .round // 此处配置实现端点圆角效果
                ))
                .rotationEffect(.degrees(-90)) // 配置进度从顶部开始计算
        }
        .padding(lineWidth/2)
    }
}

// 使用示例
struct DemoView: View {
    @State private var progress: CGFloat = 0.6
    var body: some View {
        CircularProgressView(progress: $progress)
            .frame(width: 200, height: 200)
    }
}

2. UIKit 实现(全iOS版本兼容)

通过CAShapeLayer实现,性能更高,适配更低版本系统,示例代码如下:

class CircularProgressView: UIView {
    // 进度值 取值范围0~1
    var progress: CGFloat = 0 {
        didSet {
            progressLayer.strokeEnd = progress
        }
    }
    // 环宽度
    var lineWidth: CGFloat = 16 {
        didSet {
            trackLayer.lineWidth = lineWidth
            progressLayer.lineWidth = lineWidth
            updatePath()
        }
    }
    // 背景轨道颜色
    var trackColor: UIColor = .gray.withAlphaComponent(0.2) {
        didSet {
            trackLayer.strokeColor = trackColor.cgColor
        }
    }
    // 进度环颜色
    var progressColor: UIColor = .blue {
        didSet {
            progressLayer.strokeColor = progressColor.cgColor
        }
    }
    
    private let trackLayer = CAShapeLayer()
    private let progressLayer = CAShapeLayer()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupLayers()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupLayers()
    }
    
    private func setupLayers() {
        // 配置背景轨道层
        trackLayer.fillColor = UIColor.clear.cgColor
        trackLayer.lineWidth = lineWidth
        trackLayer.strokeColor = trackColor.cgColor
        layer.addSublayer(trackLayer)
        
        // 配置进度层
        progressLayer.fillColor = UIColor.clear.cgColor
        progressLayer.lineWidth = lineWidth
        progressLayer.strokeColor = progressColor.cgColor
        progressLayer.lineCap = .round // 此处配置实现端点圆角效果
        progressLayer.strokeEnd = 0
        layer.addSublayer(progressLayer)
    }
    
    private func updatePath() {
        let center = CGPoint(x: bounds.midX, y: bounds.midY)
        let radius = min(bounds.width, bounds.height)/2 - lineWidth/2
        // 配置进度从顶部开始计算
        let path = UIBezierPath(arcCenter: center, radius: radius, startAngle: -.pi/2, endAngle: .pi * 2 - .pi/2, clockwise: true)
        trackLayer.path = path.cgPath
        progressLayer.path = path.cgPath
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        trackLayer.frame = bounds
        progressLayer.frame = bounds
        updatePath()
    }
}

// 使用示例
let progressView = CircularProgressView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
progressView.progress = 0.6

注意事项

  • 进度值的取值范围为0到1,超过范围需要自行做边界限制
  • 如果需要实现渐变颜色的进度环,只需要给进度层添加渐变遮罩即可

内容的提问来源于stack exchange,提问作者Antonio A. Chavez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 00:48:03