學習記錄#利用 UIBezierPath 實現圓環進度條,甜甜圈圖表 & 圓餅圖
Published in
13 min readJan 28, 2021
圓環進度條(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 / 100let 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