This Swift code snippet is a minimal runable code that renders a pie chart using CAShapeLayer and UIKit.
Code
PieChartsView
final public class PieChartsView: UIView {
private var data: [CGFloat]
private var shapeLayers: [CAShapeLayer] = []
public init(data: [CGFloat]) {
self.data = data
super.init(frame: .zero)
backgroundColor = .clear
setupGestureRecognizers()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
public override func draw(_ rect: CGRect) {
guard !data.isEmpty else { return }
let total = data.reduce(0, +)
let center = CGPoint(x: rect.width / 2, y: rect.height / 2)
let radius: CGFloat = min(rect.width, rect.height) / 2 - 20
let space: CGFloat = 0.1 // Space between arcs in radians
var startAngle: CGFloat = 0
for value in data {
let endAngle = startAngle + (value / total) * (2 * .pi - CGFloat(data.count) * space)
let shapeLayer = CAShapeLayer()
let path = UIBezierPath(arcCenter: center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: true)
shapeLayer.path = path.cgPath
shapeLayer.strokeColor = UIColor.random().cgColor
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineWidth = 4
shapeLayer.lineCap = .round
layer.addSublayer(shapeLayer)
shapeLayers.append(shapeLayer)
startAngle = endAngle + space
}
}
private func setupGestureRecognizers() {
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
addGestureRecognizer(tapGestureRecognizer)
}
@objc private func handleTap(_ gesture: UITapGestureRecognizer) {
let location = gesture.location(in: self)
let touchBuffer: CGFloat = 10.0 // Buffer area around the arc
for shapeLayer in shapeLayers {
if let path = shapeLayer.path {
let strokedPath = path.copy(strokingWithWidth: shapeLayer.lineWidth + touchBuffer, lineCap: .round, lineJoin: .round, miterLimit: 0)
if strokedPath.contains(location) {
shapeLayer.lineWidth = 8
shapeLayer.setNeedsDisplay()
} else {
shapeLayer.lineWidth = 4
shapeLayer.setNeedsDisplay()
}
}
}
}
}
private extension UIColor {
static func random() -> UIColor {
return UIColor(
red: .random(in: 0...1),
green: .random(in: 0...1),
blue: .random(in: 0...1),
alpha: 1.0
)
}
}
Sample ViewController
class TestVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let containerView = UIView()
containerView.backgroundColor = .clear
view.addSubview(containerView)
containerView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
containerView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
containerView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
containerView.widthAnchor.constraint(equalToConstant: 250),
containerView.heightAnchor.constraint(equalToConstant: 250)
])
let pieChartView = PieChartsView(data: [10, 20, 30, 40, 50, 60])
containerView.addSubview(pieChartView)
pieChartView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
pieChartView.topAnchor.constraint(equalTo: containerView.topAnchor),
pieChartView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor),
pieChartView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
pieChartView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor)
])
// Create the first label
let label1 = UILabel()
label1.text = "Total sum:"
label1.font = .systemFont(ofSize: 12)
label1.textColor = .gray
label1.textAlignment = .center
containerView.addSubview(label1)
let label2 = UILabel()
label2.text = "284.45USD"
label2.font = .boldSystemFont(ofSize:18)
label2.textColor = .black
containerView.addSubview(label2)
label1.translatesAutoresizingMaskIntoConstraints = false
label2.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
label1.centerXAnchor.constraint(equalTo: containerView.centerXAnchor),
label1.centerYAnchor.constraint(equalTo: containerView.centerYAnchor, constant: -10),
label2.centerXAnchor.constraint(equalTo: containerView.centerXAnchor),
label2.centerYAnchor.constraint(equalTo: containerView.centerYAnchor, constant: 10)
])
}
}
Result
In the world of SwiftUI and Swift Charts, I have some fun with UIKit to draw an interactive pie chart
— An Tran (@antranapp) October 10, 2024
The code is here: https://t.co/mvf4Z4Hy5y pic.twitter.com/A9pCb0YQ26