Drawing Shapes with Core Graphics

Core Graphics is an API included in both Cocoa and Cocoa Touch. It allows you to draw paths, shapes, shadows and gradients on the graphic destination. In this tutorial we will draw some basic shapes such as a rectangle or a circle.

Open Xcode and create a new Single View Application. For product name, use CGShapesDemo and then fill out the Organization Name, Company Identifier and Class Prefix fields with your customary values. Make sure only iPhone is selected in Devices, and that the Use Storyboards is deselected and Use Automatic Reference Counting checkboxes are selected (Unit Tests will not be necessary for this project).

Go to ViewController.xib and drag three buttons to the view. The view should look like this.

We will add a tag value to the buttons so we will know which button is pressed.Select the Button and in the Attribute Inspector change the tag value.

  • Lines button - tag value: 0
  • Rectangle Button - tag value: 1
  • Circle Button - tag value: 2

In ViewController.m in the interface section add the following IBAction method

- (IBAction)buttonPressed:(UIButton *) sender;

In ViewController.xib connect the 3 buttons to the buttonPressed method.

When the buttons are pressed a new view will be created and loaded with the corresponding shape. First create a new class ShapeView which is a subclass of UIView. At the top of ShapeView.h we will declare a enumerated type for the different shapes

typedef enum shapeTypes
{ linesShape,
rectangleShape,
circleShape
} ShapeType;

Create a ShapeType instance variable in the interface section

@interface MyClass : UIView 
{
ShapeType currentShapeType;
}

Declare a init method, which we'll need to pass the previously generated tag value from the ViewController to this View.

- (id)initWithFrame:(CGRect)frame shape:(int)shape;

In ShapesView.m change the initWithFrame method in

- (id)initWithFrame:(CGRect)frame shape:(int)shape; 
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
currentShapeType = shape;
}

return self;
}

The shape argument is assigned to the currentShapeType.

With Core Graphics, if you want to modify any view you have to subclass it and override its drawRect: method. Change the drawRect method in ShapeView.m in

- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];

switch (currentShapeType) {
case linesShape:
[self drawLines];
break;
case rectangleShape:
[self drawRectangle];
break;
case circleShape:
[self drawCircle];
break;
default:
break;
}
}

The switch statement looks at the value of the currentShapeType and calls the corresponding method.

Now let's create the methods to draw the different shapes

 

- (void)drawLines 
{
//1
CGContextRef ctx = UIGraphicsGetCurrentContext();

//2
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, 20.0, 20.0);
CGContextAddLineToPoint(ctx, 250.0, 100.0);
CGContextAddLineToPoint(ctx, 100.0f, 200.0f);
CGContextSetLineWidth(ctx, 5);

//3
CGContextClosePath(ctx);
CGContextStrokePath(ctx);
}

- (void)drawRectangle
{
CGPoint center = CGPointMake(self.frame.size.width / 2.0, self.frame.size.height / 2.0);
float rectangleWidth = 100.0;
float rectangleHeight = 100.0;

CGContextRef ctx = UIGraphicsGetCurrentContext();

//4
CGContextAddRect(ctx, CGRectMake(center.x - (0.5 * rectangleWidth), center.y - (0.5 * rectangleHeight), rectangleWidth, rectangleHeight));
CGContextSetLineWidth(ctx, 10);
CGContextSetStrokeColorWithColor(ctx, [[UIColor grayColor] CGColor]);
CGContextStrokePath(ctx);

//5
CGContextSetFillColorWithColor(ctx, [[UIColor greenColor] CGColor]);
CGContextAddRect(ctx, CGRectMake(center.x - (0.5 * rectangleWidth), center.y - (0.5 * rectangleHeight), rectangleWidth, rectangleHeight));
CGContextFillPath(ctx);
}

- (void)drawCircle
{
CGPoint center = CGPointMake(self.frame.size.width / 2.0, self.frame.size.height / 2.0);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextBeginPath(ctx);

//6 CGContextSetLineWidth(ctx, 5);
CGContextAddArc(ctx, center.x, center.y, 100.0, 0, 2*M_PI, 0);
CGContextStrokePath(ctx);
}
  1. The Graphic Context is your graphic destination. If you want to draw on a view, the view is your Graphic Context. We need to get a reference  to the Graphics Context.
  2. A path is a set of lines, arcs and curves you can draw on the current graphic context to build complex objects. Here we draw some lines and set the line width to 5.
  3. The path is closed and drawn to the graphics context.
  4. With CGContextAddRect a rectangle is drawn. the outline stroke color is gray.
  5. Here the same rectangle is defined, with a fill color of green
  6. With CGContextAddArc a circle is drawn

In ViewController.m import the ShapeView class

#import "ShapeView.h"

Now it is time to implement the buttonPressed method in ViewController.m

 

- (IBAction)buttonPressed:(UIButton *)sender 
{
ShapeView *myView = [[ShapeView alloc] initWithFrame: CGRectMake(20, 100, 280, 250) shape:sender.tag];
myView.backgroundColor = [UIColor whiteColor];

[self.view addSubview:myView];
}

The view is created and the tag property of the button is sent along. The view is assigned a white background colour and added to the main view.

Build and Run, click the buttons and the shapes are being drawn

You can download the source code of the CGShapedDemo at the ioscreator repository on github.