4
votes

I am trying to create a 200px square with rounded corners to use as an IOS toast style indication.

I have the following so far -

- (void)drawRect:(CGRect)rect {

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.1].CGColor);
    CGContextMoveToPoint(context, 10, 0);
    CGContextAddLineToPoint(context, 95, 0);
    CGContextAddArcToPoint(context, 100, 0, 100, 5, 10);
    CGContextAddLineToPoint(context, 100, 95);
    CGContextAddArcToPoint(context, 100, 100, 95, 100, 10);
    CGContextAddLineToPoint(context, 5, 100);
    CGContextAddArcToPoint(context, 0, 100, 0, 95, 10);
    CGContextAddLineToPoint(context, 0, 5);
    CGContextAddArcToPoint(context, 0, 0, 5, 0, 10);
    CGContextFillPath(context);
}

I got this far by following a tutorial - it draws a perfect 100px with rounded corners square - but I need a 150px square! I have changed every setting imaginable - with some bizzare results - but cant work out how the width height is defined!? Can anyone advise?

4
150 or 200? is not clear at meAndrea
If that is all that you are looking for then see Simon's answer. The framework provides you with everything you need. For more complex forms core graphics can be really helpful. When you draw your own drawings with core graphics then I'd suggest using variables (or constants to start with) such as with, height and conerRadius. First, it is easier to be programmed. But second and most it is more flexible. You would then just change the width and height from 100 to 150 and that's it.Hermann Klecker

4 Answers

13
votes

Update for Swift:

The below answer was correct that the time it was written for simple use cases. Things have changed a lot since then so heres an updated answer for swift.

You can create a UIView extension, to add methods to round all corners, or round specific corners. Adding @IBInspectable to the first property means it can be used in interface builder without requiring code

The second function is more complicated and can't be used as an @IBInspectable directly. It will need to be called inside the viewDidLayoutSubviews of the parent to ensure the mask doesn't cut off content as AutoLayout grows / shrinks the content.

extension UIView {

    @IBInspectable public var cornerRadius: CGFloat {
        set {
            layer.cornerRadius = newValue
        }
        get {
            return layer.cornerRadius
        }
    }

    public func roundCorners(corners: UIRectCorner, radius: CGFloat) {
        let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
        let mask = CAShapeLayer()
        mask.path = path.cgPath
        layer.mask = mask
    }
}

Once added to your project you can simply do:

myView.cornerRadius = 4

or

myView.roundCorners(corners: [.topLeft, .topRight], radius: 4)

Very old Objective-c answer:

If you import QuartzCore framework:

#import <QuartzCore/QuartzCore.h>

and add it to your project, you can use the below:

UIView *temp = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];
temp.layer.cornerRadius = 5;
10
votes

If you must draw in drawRect and other stuff will be drawn in future, then just use bezierpath, otherwise see Simon's answer for simple rounded corners on a view

- (void)drawRect:(CGRect)rect {
       [super drawRect:rect];
       [[UIColor blueColor] setFill];
       UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect /*CGRectMake(0, 0, 150, 150)*/ cornerRadius:10.0];
       [path fill];
}
5
votes
  1. Convert numbers to variables/constants.

  2. Change variables/constants values.

  3. Profit!

Here's your code, modified to show what I mean (untested):

- (void)drawRect:(CGRect)rect {
    static CGFloat length = 100;
    static CGFloat rounding = 5;

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.1].CGColor);
    CGContextMoveToPoint(context, rounding * 2, 0);
    CGContextAddLineToPoint(context, length - rounding, 0);
    CGContextAddArcToPoint(context, length, 0, length, rounding, rounding * 2);
    CGContextAddLineToPoint(context, length, length - rounding);
    CGContextAddArcToPoint(context, length, length, length - rounding, length, rounding * 2);
    CGContextAddLineToPoint(context, rounding, length);
    CGContextAddArcToPoint(context, 0, length, 0, length - rounding, rounding * 2);
    CGContextAddLineToPoint(context, 0, rounding);
    CGContextAddArcToPoint(context, 0, 0, rounding, 0, rounding * 2);
    CGContextFillPath(context);
}

I also wonder about the 10s in your code. As far as I can see they should be 5s instead. Anyways, the easier solution is to use a UIBezierPath as others have demonstrated (the layer solution does work, but it obviously won't work if you for example want to draw something below the rounded rect and something above it).

3
votes

Why don't you use a bezier path?

CGFloat radius =  4;
CGRect rect = CGRectMake(0,0,200,200);
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius];
[[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.1] setFill];
[path fill];