練習筆記48 : 利用 UIBezierPath 實現圓環進度條,甜甜圈圖表 & 圓餅圖
之前的作業用UIBezierPath跟CAShapeLayer互相搭配繪圖過
這次要練習做出三種圖表:圓環進度條/甜甜圈圖表 /圓餅圖
圓環進度條(circular progress ring)
圓環進度條的做法主要是做出一個完整的圓環circleLayer及一個進度條percentageLayer
circleLayer對應的circlePath是用 UIBezierPath(ovalIn: CGRect(x:, y: , width: , height: )) 畫出一個圓形
percentageLayer對應的percentagePath則是用UIBezierPath(arcCenter: 圓心座標, radius: 半徑, startAngle:圓弧開始角度, endAngle: 圓弧結束角度, clockwise: 是否順時針) 畫出曲線
接著將做好的兩個layer加到view上
並且可以依照需求加上文字label
import UIKit
//基本設定
let view = UIView(frame: CGRect(x: 0, y: 0, width: 2*(radius+lineWidth), height: 2*(radius+lineWidth)))
let aDegree = CGFloat.pi/180
let lineWidth = 10
let startDegree = 270
let radius = 50
let percentage :CGFloat = 60
//circleLayer
let circlePath = UIBezierPath(ovalIn: CGRect(x: lineWidth, y: lineWidth, width: radius*2, height: radius*2))
let circleLayer = CAShapeLayer()
circleLayer.path = circlePath.cgPath
circleLayer.strokeColor = UIColor.lightGray.cgColor
circleLayer.lineWidth = CGFloat(lineWidth)
circleLayer.fillColor = UIColor.clear.cgColor
//percentageLayer
let percentagePath = UIBezierPath(arcCenter: CGPoint(x: lineWidth+radius, y: lineWidth+radius), radius: CGFloat(radius), startAngle: CGFloat(startDegree)*aDegree, endAngle: (CGFloat(startDegree)+percentage/100*360)*aDegree, clockwise: true)
let percentageLayer = CAShapeLayer()
percentageLayer.path = percentagePath.cgPath
percentageLayer.strokeColor = UIColor.blue.cgColor
percentageLayer.lineWidth = CGFloat(lineWidth)
percentageLayer.fillColor = UIColor.clear.cgColor
percentageLayer.lineCap = .round
//label
let label = UILabel(frame: view.frame)
label.text = "\(percentage)%"
label.textAlignment = .center
//各個 layer/view 加入view
view.layer.addSublayer(circleLayer)
view.layer.addSublayer(percentageLayer)
view.addSubview(label)
view
甜甜圈圖表(donut chart)
製作甜甜圈圖表時先建立一個array儲存各個比例的值
再利用for迴圈產生各個比例對應的圖
percentageLayer的圖形可以透過設定lineWidth 將線條加寬製造出中空的甜甜圈狀 並用strokeColor更改顏色
最後建立一個產生label的function ㄧ起加入for迴圈裡
import UIKit
//基本設定
let aDegree = CGFloat.pi/180
let lineWidth = 50
let radius = 50
let view = UIView(frame: CGRect(x: 0, y: 0, width: (lineWidth+radius)*2, height: (lineWidth+radius)*2))
let center = CGPoint(x: Double(lineWidth+radius), y: Double(lineWidth+radius))
var percentages : [CGFloat] = [30,25,45]
var startDegree : CGFloat = 270
var endDegree : CGFloat = 0
//產生label
func createLabel(percentage:CGFloat,startDegree:CGFloat) -> UILabel{
//圓弧中心放label
let labelCenterDegree = startDegree + percentage/100*360/2
let labelPath = UIBezierPath(arcCenter: center, radius: CGFloat(radius), startAngle: labelCenterDegree*aDegree, endAngle: labelCenterDegree*aDegree, clockwise: true)
let label = UILabel(frame: CGRect(x: 0, y:0, width: 30, height: 15))
label.text = "\(percentage)%"
label.backgroundColor = UIColor.white
label.font = UIFont.systemFont(ofSize: 8)
label.textAlignment = .center
label.center = labelPath.currentPoint
return label
}
//用for迴圈產生各個比例的圖
for percentage in percentages {
endDegree = startDegree+percentage/100*360
//畫路徑
let percentagePath = UIBezierPath(arcCenter: center, radius: CGFloat(radius), startAngle: startDegree*aDegree, endAngle: endDegree*aDegree, clockwise: true)
//產生layer
let percentageLayer = CAShapeLayer()
percentageLayer.path = percentagePath.cgPath
percentageLayer.strokeColor = CGColor(red:CGFloat.random(in: 0...1), green: CGFloat.random(in: 0...1), blue: CGFloat.random(in: 0...1), alpha: 1)
percentageLayer.lineWidth = CGFloat(lineWidth)
percentageLayer.fillColor = UIColor.clear.cgColor
//將layer加到view上
view.layer.addSublayer(percentageLayer)
//將label加到view上
view.addSubview(createLabel(percentage: percentage, startDegree: startDegree))
//讓下一段弧線startDegree是上一段的endDegree
startDegree = endDegree
}
view
圓餅圖(pie chart)
圓餅圖的製作直接用剛剛甜甜圈圖表來改~
最主要的不同是用UIBezierPath產生percentagePath路徑時
要先將繪製的起點用.move(to:)指定為view的中心
再用.addArc畫出由中心點向外延伸的扇形
並設定percentageLayer的fillColor
最後再微調一下label的大小跟位置就完成了~~
import UIKit
//基本設定
let aDegree = CGFloat.pi/180
let lineWidth = 10
let radius = 50
let view = UIView(frame: CGRect(x: 0, y: 0, width: (lineWidth+radius)*2, height: (lineWidth+radius)*2))
let center = CGPoint(x: Double(lineWidth+radius), y: Double(lineWidth+radius))
var percentages : [CGFloat] = [30,25,45]
var startDegree : CGFloat = 270
var endDegree : CGFloat = 0
//產生label
func createLabel(percentage:CGFloat,startDegree:CGFloat) -> UILabel{
//圓弧中心放label
let labelCenterDegree = startDegree + percentage/100*360/2
let labelPath = UIBezierPath(arcCenter: view.center, radius: CGFloat(radius/2), startAngle: labelCenterDegree*aDegree, endAngle: labelCenterDegree*aDegree, clockwise: true)
let label = UILabel(frame: CGRect(x: 0, y:0, width: 25, height: 10))
label.text = "\(percentage)%"
label.backgroundColor = UIColor.white
label.font = UIFont.systemFont(ofSize: 7)
label.textAlignment = .center
label.center = labelPath.currentPoint
return label
}
//用for迴圈產生各個比例的圖
for percentage in percentages {
endDegree = startDegree+percentage/100*360
//畫路徑 產生扇形圖案
let percentagePath = UIBezierPath()
percentagePath.move(to: view.center)
percentagePath.addArc(withCenter: view.center, radius: CGFloat(radius), startAngle: startDegree*aDegree, endAngle: endDegree*aDegree, clockwise: true)
//產生layer
let percentageLayer = CAShapeLayer()
percentageLayer.path = percentagePath.cgPath
percentageLayer.fillColor = CGColor(red:CGFloat.random(in: 0...1), green: CGFloat.random(in: 0...1), blue: CGFloat.random(in: 0...1), alpha: 1)
//將layer加到view上
view.layer.addSublayer(percentageLayer)
//將label加到view上
view.addSubview(createLabel(percentage: percentage, startDegree: startDegree))
//讓下一段弧線startDegree是上一段的endDegree
startDegree = endDegree
}
view
之前雖然已經做過幾個UIBezierPath的作業
但是我還是對UIBezierPath有點恐懼😭
覺得算位置角度好難😭😭😭
不過總算把這個作業完成了🥹