Search code examples
iosswiftcore-graphics

How do I use this circle drawing code in a UIView?


I am making an app including some breathing techniques for a client. What he wants is to have a circle in the middle. For breathing in it becomes bigger, for breathing out tinier. The thing is, that he would like to have a cool animated circle in the middle, not just a standard one. I showed him this picture from YouTube: Circle

The code used in the video looks like this:

func drawRotatedSquares() {
    UIGraphicsBeginImageContextWithOptions(CGSize(width: 512, height: 512), false, 0)
    let context = UIGraphicsGetCurrentContext()

    context!.translateBy(x: 256, y: 256)
    let rotations = 16
    let amount = M_PI_2 / Double(rotations)

    for i in 0 ..< rotations {
        context!.rotate(by: CGFloat(amount))
        //context!.addRect(context, CGRect(x: -128, y: -128, width: 256, height: 256))
        context!.addRect(CGRect(x: -128, y: -128, width: 256, height: 256))
    }

    context!.setStrokeColor(UIColor.black as! CGColor)

    let img = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    imageView.image = img
}

But if I run it, my simulator shows just a white screen. How do I get this circle into my Swift 3 app and how would the code look like? And is it possible not to show it in an ImageView but simply in a view?

Thank you very much!


Solution

  • Here is an implementation as a UIView subclass.

    To set up:

    1. Add this class to your Swift project.
    2. Add a UIView to your Storyboard and change the class to Circle.
    3. Add an outlet to your viewController

      @IBOutlet var circle: Circle!
      
    4. Change the value of multiplier to change the size of the circle.

      circle.multiplier = 0.5  // 50% of size of view
      

    class Circle: UIView {
        var multiplier: CGFloat = 1.0 {
            didSet {
                setNeedsDisplay()
            }
        }
    
        override func draw(_ rect: CGRect) {
            let context = UIGraphicsGetCurrentContext()!
    
            // Calculate size of square edge that fits into the view   
            let size = min(bounds.width, bounds.height) * multiplier / CGFloat(sqrt(2)) / 2
    
            // Move origin to center of the view            
            context.translateBy(x: center.x, y: center.y)
    
            // Create a path to draw a square    
            let path = UIBezierPath()
            path.move(to: CGPoint(x: -size, y: -size))
            path.addLine(to: CGPoint(x: -size, y: size))
            path.addLine(to: CGPoint(x: size, y: size))
            path.addLine(to: CGPoint(x: size, y: -size))
            path.close()
    
            UIColor.black.setStroke()
    
            let rotations = 16
            let amount = .pi / 2 / Double(rotations)
    
            for _ in 0 ..< rotations {
                // Rotate the context
                context.rotate(by: CGFloat(amount))
    
                // Draw a square
                path.stroke()
            }
        }
    }
    

    Here it is running in a Playground:

    Demo of Circle in a Playground