Search code examples
iosobjective-ccocoa-touchcore-animationcashapelayer

How to draw slices in semicircle shape layers in objective-c


I have drawn the semicircle shape by using following code

- (void)drawRect:(CGRect)rect
{
    UIBezierPath *bezierPath = [UIBezierPath bezierPath];
    [bezierPath addArcWithCenter:CGPointMake(self.frame.size.width, self.frame.size.height/2) radius:150 startAngle:0 endAngle:2 * M_PI clockwise:YES];
     CAShapeLayer *progressLayer = [[CAShapeLayer alloc] init];
    [progressLayer setPath:bezierPath.CGPath];
    [progressLayer setStrokeColor:[UIColor colorWithWhite:1. alpha:.2].CGColor];
    [progressLayer setFillColor:[UIColor colorWithRed:67.0/255.0 green:144.0/255.0 blue:246.0/255.0 alpha:1.0].CGColor];
    [progressLayer setLineWidth:.7 * self.bounds.size.width];
    [[self layer] addSublayer:progressLayer];
      // [self drawWheel];
  }

I want to draw a slices like pie in a semicircle using objective-c that should match exactly like image as shown below

Can anyone suggest me any solution please


Solution

  • Add this code in your drawRect(_:)

    let radius = min(bounds.size.width, bounds.size.height) / 2;
    let center = CGPoint.init(x: bounds.size.width / 2, y: bounds.size.height / 2)
    let sliceCount = 6;
    
    let slicePath = UIBezierPath.init()
    slicePath.lineWidth = 1;
    slicePath.move(to: center)
    
    var angle: CGFloat = 0 - (CGFloat.pi / 2);
    var interval: CGFloat = (CGFloat.pi) / CGFloat(sliceCount)
    
    
    
    for i in 0 ... sliceCount {
        let x = center.x + (radius * cos(angle))
        let y = center.y + (radius * sin(angle))
        slicePath.addLine(to: CGPoint.init(x: x, y: y))
        slicePath.move(to: center)
        angle -= interval;
    }
    
    UIColor.white.setStroke()
    slicePath.stroke()
    

    Here is the result.enter image description here

    Updated Another code that's very similar to your goal

    override func draw(_ rect: CGRect) {
    
        let radius = min(bounds.size.width, bounds.size.height) / 2;
        let center = CGPoint.init(x: bounds.size.width, y: bounds.size.height / 2)
        let sliceCount = 6;
    
        let semiCirclePath = UIBezierPath.init()
        semiCirclePath.move(to: center)
        semiCirclePath.addArc(withCenter: center, radius: radius, startAngle: CGFloat.pi / 2, endAngle: CGFloat.pi + (CGFloat.pi / 2) , clockwise: true)
        semiCirclePath.close()
        UIColor.blue.setFill()
        semiCirclePath.fill()
    
    
    
        let slicePath = UIBezierPath.init()
        slicePath.lineWidth = 1;
        slicePath.move(to: center)
    
        var angle: CGFloat = 0 - (CGFloat.pi / 2);
        var interval: CGFloat = (CGFloat.pi) / CGFloat(sliceCount)
    
    
    
        for i in 0 ... sliceCount {
            let x = center.x + (radius * cos(angle))
            let y = center.y + (radius * sin(angle))
            slicePath.addLine(to: CGPoint.init(x: x, y: y))
            slicePath.move(to: center)
            angle -= interval;
        }
    
        UIColor.white.setStroke()
        slicePath.stroke()
    
        semiCirclePath.removeAllPoints()
        semiCirclePath.move(to: center)
        semiCirclePath.addArc(withCenter: center, radius: 30, startAngle: CGFloat.pi / 2, endAngle: CGFloat.pi + (CGFloat.pi / 2) , clockwise: true)
        UIColor.lightGray.setFill()
        semiCirclePath.fill()
    }
    

    Here what it looks like,

    enter image description here

    Updated second time For the one that's completely looked like

    override func draw(_ rect: CGRect) {
    
        let radius = min(bounds.size.width, bounds.size.height) / 2;
        let center = CGPoint.init(x: bounds.size.width, y: bounds.size.height / 2)
        let selectedSliceIndex = 2;
        let sliceCount = 6;
    
        let slicePath = UIBezierPath.init()
        let selectedSlicePath = UIBezierPath.init()
        slicePath.lineWidth = 1;
        slicePath.move(to: center)
    
        var angle: CGFloat = 0 - (CGFloat.pi / 2);
        let interval: CGFloat = (CGFloat.pi) / CGFloat(sliceCount)
    
        for i in 0 ... sliceCount {
            let x = center.x + (radius * cos(angle))
            let y = center.y + (radius * sin(angle))
            slicePath.addLine(to: CGPoint.init(x: x, y: y))
            slicePath.move(to: center)
    
    
            if i == selectedSliceIndex {
                selectedSlicePath.move(to: center)
                selectedSlicePath.addArc(withCenter: center, radius: radius, startAngle: angle - interval, endAngle: angle, clockwise: true)
                selectedSlicePath.close()
            }
    
            angle -= interval;
        }
    
        // outer blue circle
        let semiCirclePath = UIBezierPath.init()
        semiCirclePath.move(to: center)
        semiCirclePath.addArc(withCenter: center, radius: radius, startAngle: CGFloat.pi / 2, endAngle: CGFloat.pi + (CGFloat.pi / 2) , clockwise: true)
        semiCirclePath.close()
        UIColor.blue.setFill()
        semiCirclePath.fill()
    
        // lines
        UIColor.white.setStroke()
        slicePath.stroke()
    
        // selected slice
        UIColor.lightGray.setFill()
        selectedSlicePath.fill()
        UIColor.clear.setFill()
    
        // inner gray circle
        semiCirclePath.removeAllPoints()
        semiCirclePath.move(to: center)
        semiCirclePath.addArc(withCenter: center, radius: 30, startAngle: CGFloat.pi / 2, endAngle: CGFloat.pi + (CGFloat.pi / 2) , clockwise: true)
        UIColor.lightGray.setFill()
        semiCirclePath.fill()
    
    }
    

    enter image description here

    You might need to adjust some values to look beautiful.

    I Moved the view's frame inside ViewController FYI.