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

