iOS Swift 圆图

iOS Swift circle chart

关于如何为 iOS Swift 实施以下进度表有什么建议吗?

只需将其分解为单独的步骤即可。

第一个问题是如何绘制各个刻度线。

一种方法是使用 UIBezierPath:

绘制四笔画
  • 外径顺时针圆弧;
  • 一条线到内径;
  • a counter-clockwise 内径圆弧;和
  • 一条线回到外半径。

事实证明,你可以跳过这两行,只添加那两条弧线,然后关闭路径,你就完成了。 UIBezierPath 将为您添加两条弧线之间的线。例如:

let startAngle: CGFloat = 2 * .pi * (CGFloat(i) - 0.2) / CGFloat(tickCount)
let endAngle: CGFloat = 2 * .pi * (CGFloat(i) + 0.2) / CGFloat(tickCount)

// create path for individual tickmark

let path = UIBezierPath()
path.addArc(withCenter: center, radius: outerRadius, startAngle: startAngle, endAngle: endAngle, clockwise: true)
path.addArc(withCenter: center, radius: innerRadius, startAngle: endAngle, endAngle: startAngle, clockwise: false)
path.close()

// use that path in a `CAShapeLayer`

let shapeLayer = CAShapeLayer()
shapeLayer.fillColor = …
shapeLayer.strokeColor = UIColor.clear.cgColor
shapeLayer.path = path.cgPath

// add it to our view’s `layer`

view.layer.addSublayer(shapeLayer)

0tickCount 之间对 i 重复此操作,其中 tickCount90,您有九十个标记:

显然,使用任何你想要的颜色,将进度范围之外的颜色设为灰色等。但希望这能说明如何使用 UIBezierPath 渲染两个弧并为每个弧填充形状的基本思想具有指定颜色的相应刻度线。


例如

class CircularTickView: UIView {
    var progress: CGFloat = 0.7 { didSet { setNeedsLayout() } }

    private var shapeLayers: [CAShapeLayer] = []
    private let startHue: CGFloat = 0.33
    private let endHue: CGFloat = 0.66
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        shapeLayers.forEach { [=11=].removeFromSuperlayer() }
        shapeLayers = []
        
        let outerRadius = min(bounds.width, bounds.height) / 2
        let innerRadius = outerRadius * 0.7
        let center = CGPoint(x: bounds.midX, y: bounds.midY)
        let tickCount = 90
        
        for i in 0 ..< tickCount {
            let shapeLayer = CAShapeLayer()
            shapeLayer.fillColor = color(percent: CGFloat(i) / CGFloat(tickCount)).cgColor
            shapeLayer.strokeColor = UIColor.clear.cgColor
            
            let startAngle: CGFloat = 2 * .pi * (CGFloat(i) - 0.2) / CGFloat(tickCount)
            let endAngle: CGFloat = 2 * .pi * (CGFloat(i) + 0.2) / CGFloat(tickCount)
            
            let path = UIBezierPath()
            path.addArc(withCenter: center, radius: outerRadius, startAngle: startAngle, endAngle: endAngle, clockwise: true)
            path.addArc(withCenter: center, radius: innerRadius, startAngle: endAngle, endAngle: startAngle, clockwise: false)
            path.close()
            shapeLayer.path = path.cgPath
            
            layer.addSublayer(shapeLayer)
            shapeLayers.append(shapeLayer)
        }
    }

    private func color(percent: CGFloat) -> UIColor {
        if percent > progress {
            return .lightGray
        } 
        
        let hue = (endHue - startHue) * percent + startHue
        return UIColor(hue: hue, saturation: 1, brightness: 1, alpha: 1)
    }
}

显然,您需要根据自己的喜好进行调整。也许改变颜色算法。也许从 12 点而不是 3 点开始。等等。细节不如摸索如何添加带有路径的形状图层到 UI.

的基本概念重要。