2

I'm trying to create a very simple colored circle inside a UIView with a slice cut out or in a different color, something like this:

enter image description here

I expected that this would be very simple and would only require a few lines of code since CAShapeLayer allows you to create all sorts of shapes. However, it seems that this is a lot more complicated than I thought since there barely any useful tutorials online on how to do this. Using third-party libraries for something as simple as this seems a bit overkill, so I prefer a solution with UIKit classes only. Any ideas? Thanks in advance!

Freddy Benson
  • 735
  • 4
  • 11
  • 30
  • 1
    "I thought since there barely any useful tutorials online on how to do this". Like which one? I'm not criticizing the tutorials (I didn't see them), but what is your issue exactly? I guess the tutorial are about the logic behind the shapes, but don't show your exact needs? Is it about maths? Get angle, find the different points, etc. Are you even able to draw it with custom UIView (withouth CAShaplayer, but with UIBezierPaths)? What's your current code? – Larme Jul 17 '18 at 20:54
  • 1
    [Maybe](https://stackoverflow.com/questions/29616992/how-do-i-draw-a-circle-in-ios-swift), [Maybe](https://www.raywenderlich.com/162315/core-graphics-tutorial-part-1-getting-started), [maybe](https://www.hackingwithswift.com/example-code/core-graphics/how-to-draw-a-circle-using-core-graphics-addellipsein), [maybe](https://www.ioscreator.com/tutorials/drawing-shapes-core-graphics-tutorial-ios10), [maybe](https://stackoverflow.com/questions/35752762/making-a-pie-chart-using-core-graphics), [maybe](https://gist.github.com/sketchytech/2a69ad937b4995af40a7) – MadProgrammer Jul 17 '18 at 20:58
  • [Possibly](http://sketchytech.blogspot.com/2016/02/swift-going-round-in-semicircles-with.html) - on a side note. You can do this using `UIView#drawRect` and drawing to the underlying graphics context, but I think `CALayer` is better optimised, consider playing around with both and see which fits your needs – MadProgrammer Jul 17 '18 at 20:59
  • Thanks @MadProgrammer, the last 2 links look very promising. I think that's exactly what I'm looking for, but I'll have to try it out first. – Freddy Benson Jul 17 '18 at 21:16

1 Answers1

3

According to this Thread after updating to swift 4 and editing to satisfy your needs ( Left the borders as an exercise =D )

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let pieChart = PieChart(frame: CGRect(x: self.view.center.x, y: self.view.center.y, width: 300.0, height: 300.0))
        pieChart.backgroundColor = UIColor.clear
        self.view.addSubview(pieChart)
        pieChart.center = self.view.center
    }

}

class PieChart : UIView {

    override func draw(_ rect: CGRect) {

        drawSlice(rect, startPercent: 0, endPercent: 100, color: UIColor.gray)
        drawSlice(rect, startPercent: 30, endPercent: 65, color: UIColor.red)
    }

    private func drawSlice(_ rect: CGRect, startPercent: CGFloat, endPercent: CGFloat, color: UIColor) {
        let center = CGPoint(x: rect.origin.x + rect.width / 2, y: rect.origin.y + rect.height / 2)
        let radius = min(rect.width, rect.height) / 2
        let startAngle = startPercent / 100 * CGFloat(Double.pi) * 2 - CGFloat(Double.pi)
        let endAngle = endPercent / 100 * CGFloat(Double.pi) * 2 - CGFloat(Double.pi)
        let path = UIBezierPath()
        path.move(to: center)
        path.addArc(withCenter: center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: true)
        path.close()
        path.stroke()
        color.setFill()
        path.fill()
    }
}

enter image description here

Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
  • 1
    YES! Thank you! These were the "few lines of code" I was looking for to do something as simple as this. Since I don't have a lot of experience with `UIBezierPath`, that was the only confusing part for me, but now I got it. Oh by the way, thanks for the exercise, but I actually didn't even need the borders in my circle =D That was the closest image I could find to show everyone what I was trying to achieve, but the result I got from the code above (without the borders) is exactly what I needed. That means I was gonna get rid of the borders anyway :) – Freddy Benson Jul 17 '18 at 21:46
  • oh no my exercise =D – Shehata Gamal Jul 17 '18 at 21:51
  • Swift is a type inferred language. Why not simply `let startAngle = startPercent / 100 * .pi * 2 - .pi` and `let endAngle = endPercent / 100 * .pi * 2 - .pi` as well? – Leo Dabus Jul 17 '18 at 23:51