Search code examples
iosswiftuibezierpath

Draw half circuler image like meter using UIBezierPath...!


I need to draw image as shown in this link.

I have implemented it. And it's like in this link.

My View Controller code contains below code

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let width: CGFloat = 240
        let height: CGFloat = 240

        let demoView = DemoView(frame: CGRect(x: self.view.frame.size.width/2 - width/2,
                                              y: self.view.frame.size.height/2 - height/2,
                                              width: width,
                                              height: height))

        let subView = UIView.init(frame: (CGRect(x: demoView.frame.origin.x - width,
                                          y: demoView.frame.origin.y,
                                          width: width * 2,
                                          height: height * 2)))

        self.view.addSubview(demoView)
        self.view.addSubview(subView)

        subView.backgroundColor = UIColor.lightGray.withAlphaComponent(0.5)
        subView.layer.cornerRadius = subView.frame.size.height / 2
    }

}

import UIKit

class DemoView: UIView {
    var path: UIBezierPath!

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.backgroundColor = UIColor.darkGray
    }

    override func draw(_ rect: CGRect) {
        self.createTriangle()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    func createTriangle() {            
        let count : Int = 9
        let gap : CGFloat = 3
        let yValue : CGFloat = CGFloat(self.frame.size.width - ((CGFloat(count - 1)) * gap)) / CGFloat(count);

        for a in 0 ..< count {
            let i : CGFloat = CGFloat(a)

            let path1: UIBezierPath! = UIBezierPath()
            path1.move(to: CGPoint(x: 0.0, y: self.frame.size.height))
            path1.addLine(to: CGPoint(x: (yValue * i) > 0 ? (yValue * i) + i*gap : 0, y: (yValue * i) > 0 ? (yValue * i) + i*gap : 0))
            path1.addLine(to: CGPoint(x:yValue * (i+1) + i*gap, y: yValue * (i+1) + i*gap))
            path1.close()
            UIColor.orange.setFill()
            path1.fill()
        }
    }
}

Can anyone help me to achieve this thing?

Edit image :i have updated image related issue


Solution

  • Is this the result your want ?

    enter image description here

    The way I did it isn't with triangles but Arcs. Add createPie() in your DemoView class and call it in draw(:) instead of your createTriangle().

    This is my code:

    func createPie() {
        // 2 vars to configure width of gap/banches
        var branchAmount = 10
        var gapAngle = CGFloat.pi / 100
    
        let startAngle = 3 * CGFloat.pi / 2
        let endAngle = 2 * CGFloat.pi
        let branchAngle = (endAngle - startAngle - (CGFloat(branchAmount) - 1) * gapAngle) / CGFloat(branchAmount)
    
        let paths = UIBezierPath()
    
        for i in 0..<branchAmount {
            paths.move(to: CGPoint(x: 0.0, y: self.frame.size.height))
            paths.addArc(withCenter: CGPoint(x: 0, y: self.frame.size.height),
                         radius: self.frame.size.height,
                         startAngle: startAngle + CGFloat(i) * (branchAngle + gapAngle),
                         endAngle: startAngle + CGFloat(i) * (branchAngle + gapAngle) + branchAngle,
                         clockwise: true)
        }
        paths.close()
        UIColor.orange.setFill()
        paths.fill()
    }
    

    Cheers!

    EDIT: If you want to add a circular mask you and add this in the end of createPie() (which is no longer really a pie now..):

        // Circular mask
        let maskLayer = CAShapeLayer()
        let maskPath = UIBezierPath(rect: bounds)
        maskLayer.fillRule = kCAFillRuleEvenOdd  // Circle will be substracted to the mask thanks to this
        maskPath.move(to: CGPoint(x: 0.0, y: frame.size.height))
        maskPath.addArc(withCenter: CGPoint(x: 0, y: frame.size.height), radius: maskRadius, startAngle: startAngle, endAngle: endAngle, clockwise: true)
        maskLayer.path = maskPath.cgPath
        layer.mask = maskLayer
    

    It just adds mask composed of the subtraction of bounds and the circle of origin (0, height)

    enter image description here