學習記錄#利用 UIBezierPath 實現圓環進度條,甜甜圈圖表 & 圓餅圖

甜甜圈圖表上標示文字

圓環進度條(circular progress ring)

let aDegree = CGFloat.pi / 180  // 每度let lineWidth: CGFloat = 20  // 線條(內徑)寬度let radius: CGFloat = 80  // 圓心的距離let startDegree: CGFloat = 270   // 起點let percentage: CGFloat = 30 //百分比//繪製一個圓形當底let circlePath = UIBezierPath(ovalIn: CGRect(x: lineWidth, y: lineWidth, width: radius*2, height: radius*2))let circleLayer = CAShapeLayer()circleLayer.path = circlePath.cgPathcircleLayer.strokeColor = UIColor.gray.cgColor  //線條顏色circleLayer.lineWidth = lineWidth  //線條粗細circleLayer.fillColor = UIColor.clear.cgColor  //背景顏色//繪製另一個百分比圓形let percentagePath = UIBezierPath(arcCenter: CGPoint(x: lineWidth + radius, y: lineWidth + radius), radius: radius, startAngle: aDegree * startDegree, endAngle: aDegree * (startDegree + 360 * percentage / 100), clockwise: true)let percentageLayer = CAShapeLayer()percentageLayer.path = percentagePath.cgPathpercentageLayer.strokeColor  = UIColor(red: 1, green: 1, blue: 0, alpha: 1).cgColor   //線條顏色percentageLayer.lineWidth = lineWidth  //線條粗細percentageLayer.lineCap = .round //調整線條端點的形狀percentageLayer.fillColor = UIColor.clear.cgColor  //背景顏色//顯示數值let label = UILabel(frame: CGRect(x: 0, y: 0, width: 2*(radius+lineWidth), height: 2*(radius+lineWidth)))label.textAlignment = .centerlabel.text = "\(percentage)%"let view = UIView(frame: label.frame)view.layer.addSublayer(circleLayer)view.layer.addSublayer(percentageLayer)view.addSubview(label)view

關於圓上的角度,可參考以下圖片的說明。一般常見的圓環進度條都是從 270 度的地方開始,因此我們以它為起點設定 startAngle,endAngle 則用 270 再加上 360 * percentage / 100 得到終點所在的角度。

甜甜圈圖表(donut chart)

let aDegree = CGFloat.pi / 180  // 每度let lineWidth: CGFloat = 40  // 線條(內徑)寬度let radius: CGFloat = 40  // 圓心的距離var startDegree: CGFloat = 270  // 起點let view = UIView(frame: CGRect(x: 0, y: 0, width: 2*(radius+lineWidth), height: 2*(radius+lineWidth))) //做一個View長寬=(radius+lineWidth)view.backgroundColor = .white // 背景色var percentages: [CGFloat] = [30, 30, 40]  //百分比值//將percentages的值帶入for percentage in percentages {let endDegree = startDegree + 360 * percentage / 100 //終點所在的角度let percentagePath = UIBezierPath(arcCenter: CGPoint(x: lineWidth + radius, y: lineWidth + radius), radius: radius, startAngle: aDegree * startDegree, endAngle: aDegree * endDegree, clockwise: true)let percentageLayer = CAShapeLayer()percentageLayer.path = percentagePath.cgPathpercentageLayer.strokeColor  = UIColor(red: CGFloat.random(in: 0...1), green: CGFloat.random(in: 0...1), blue: CGFloat.random(in: 0...1), alpha: 1).cgColor //隨機出色percentageLayer.lineWidth = lineWidth  //線條粗細percentageLayer.fillColor = UIColor.clear.cgColor //背景顏色view.layer.addSublayer(percentageLayer)startDegree = endDegree // 終點的度數 = 下次起點度數}view

甜甜圈圖表上標示文字

//計算圓弧中心的角度
let textCenterDegree = startDegree + 360 * percentage / 2 / 100
let textPath = UIBezierPath(arcCenter: CGPoint(x: lineWidth + radius, y: lineWidth + radius), radius: radius, startAngle: aDegree * textCenterDegree, endAngle: aDegree * textCenterDegree, clockwise: true)//做一個label
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 50, height: 30))
label.backgroundColor = UIColor.systemYellow //背景label.font = UIFont.systemFont(ofSize: 12) //字體大小label.text = "\(percentage)%"label.sizeToFit() //讓文字的frame自適應內容大小label.center = textPath.currentPoint //label 的中心座標

解答寫的好漂亮,但不知道如何改成限定顯示顏色...只好來一層一層加上去

三元色
let aDegree = CGFloat.pi / 180  // 每度let lineWidth: CGFloat = 40  // 線條(內徑)寬度let radius: CGFloat = 40  // 圓心的距離var startDegree: CGFloat = 270  // 起點let percentage: CGFloat = 20 //first百分比let percentage1: CGFloat = 50 //second百分比let percentage2: CGFloat = 30 //three百分比let view = UIView(frame: CGRect(x: 0, y: 0, width: 2*(radius+lineWidth), height: 2*(radius+lineWidth))) //做一個View長寬=(radius+lineWidth)view.backgroundColor = .white // 背景色//畫第一個百分比let percentagePath = UIBezierPath(arcCenter: CGPoint(x: lineWidth + radius, y: lineWidth + radius), radius: radius, startAngle: aDegree * startDegree, endAngle: aDegree * (startDegree + 360 * percentage / 100), clockwise: true)let percentageLayer = CAShapeLayer()percentageLayer.path = percentagePath.cgPathpercentageLayer.strokeColor  = UIColor(red: 1, green: 0, blue: 0, alpha: 1).cgColorpercentageLayer.lineWidth = lineWidth  //線條粗細percentageLayer.fillColor = UIColor.clear.cgColor //背景顏色//畫第二個百分比let percentagePath1 = UIBezierPath(arcCenter: CGPoint(x: lineWidth + radius, y: lineWidth + radius), radius: radius, startAngle: aDegree * (startDegree + 360 * percentage / 100), endAngle: aDegree * ((startDegree + 360 * percentage / 100) + 360 * percentage1 / 100), clockwise: true)let percentageLayer1 = CAShapeLayer()percentageLayer1.path = percentagePath1.cgPathpercentageLayer1.strokeColor  = UIColor(red: 1, green: 1, blue: 0, alpha: 1).cgColorpercentageLayer1.lineWidth = lineWidth  //線條粗細percentageLayer1.fillColor = UIColor.clear.cgColor //背景顏色//畫第三個百分比let percentagePath2 = UIBezierPath(arcCenter: CGPoint(x: lineWidth + radius, y: lineWidth + radius), radius: radius, startAngle: aDegree * ((startDegree + 360 * percentage / 100) + 360 * percentage1 / 100), endAngle: aDegree * startDegree, clockwise: true)let percentageLayer2 = CAShapeLayer()percentageLayer2.path = percentagePath2.cgPathpercentageLayer2.strokeColor  = UIColor(red: 0, green: 0, blue: 1, alpha: 1).cgColorpercentageLayer2.lineWidth = lineWidth  //線條粗細percentageLayer2.fillColor = UIColor.clear.cgColor //背景顏色view.layer.addSublayer(percentageLayer)view.layer.addSublayer(percentageLayer1)view.layer.addSublayer(percentageLayer2)view

圓餅圖(pie chart)

let aDegree = CGFloat.pi / 180  // 每度let radius: CGFloat = 40  // 圓心的距離var startDegree: CGFloat = 270  // 起點let view = UIView(frame: CGRect(x: 0, y: 0, width: 2*(radius), height: 2*(radius))) //做一個Viewview.backgroundColor = .white // 背景色var percentages: [CGFloat] = [20,20,30,30]  //百分比值//將percentages的值帶入for percentage in percentages {let endDegree = startDegree + 360 * percentage / 100 //終點所在的角度let percentagePath = UIBezierPath()percentagePath.move(to: view.center) //移動到圓心percentagePath.addArc(withCenter: view.center, radius: radius, startAngle: aDegree * startDegree, endAngle: aDegree * endDegree, clockwise: true) //畫圓弧let percentageLayer = CAShapeLayer()percentageLayer.path = percentagePath.cgPathpercentageLayer.fillColor  = UIColor(red: CGFloat.random(in: 0...1), green: CGFloat.random(in: 0...1), blue: CGFloat.random(in: 0...1), alpha: 1).cgColor //隨機出色view.layer.addSublayer(percentageLayer)startDegree = endDegree // 終點的度數 = 下次起點度數}view

最後就在圓餅圖(pie chart)上也要標示文字

--

--