Drawing a custom-shaped background view with a CAShapeLayer is an easy way, how to decorate the app and make its titles or headers more distinguished.
The demo app
The demo app for this tutorial contains only one view with a background image, a label and its background view.
You can find the complete code here (tested with Xcode 6 beta 6):
Open Xcode and Create a new project by choosing the Single View Application template. If you’re using XCode 6, choose whether Swift or Objective-C on the screen. This tutorial covers both Swift and Objective-C.
Open the Main.storyboard file. Drag a new imageview to the main view.
Now add a header background view. Setup its position and height constraints.
Let’s now add a header label. Setup its position and height constraints.
Setup an “equal width constraint” for the header label and its background view. Set the multiplier to 1.35 – the background view will be slightly bigger than the label.
Set the custom class of the background view to the TriangleView.
Now create the TriangleView class and override the drawRect method of UIView.
In the drawRect method we will create two CAShapeLayers – one to mask the view’s layer (to achieve the custom shape) and another to draw the white border around the shape.
Let’s start with the first CAShapeLayer – create it and set its frame to match our view’s bounds:
CAShapeLayer *mask = [[CAShapeLayer alloc] init];
mask.frame = self.layer.bounds;
var mask = CAShapeLayer()
mask.frame = self.layer.bounds
Now it’s time to create the custom shaped path. We’ll start at the 0-point and move back to it with a small offset:
CGFloat width = self.layer.frame.size.width;
CGFloat height = self.layer.frame.size.height;
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, nil, 30, 0);
CGPathAddLineToPoint(path, nil, width, 0);
CGPathAddLineToPoint(path, nil, width, height);
CGPathAddLineToPoint(path, nil, 0, height);
CGPathAddLineToPoint(path, nil, 30, 0);
mask.path = path;
let width = self.layer.frame.size.width
let height = self.layer.frame.size.height
var path = CGPathCreateMutable()
CGPathMoveToPoint(path, nil, 30, 0)
CGPathAddLineToPoint(path, nil, width, 0)
CGPathAddLineToPoint(path, nil, width, height)
CGPathAddLineToPoint(path, nil, 0, height)
CGPathAddLineToPoint(path, nil, 30, 0)
mask.path = path
Note, that it is not needed to call CGPathRelease in Swift, because Core Foundation objects are automatically memory-mapped by Swift.
The last thing is to set the layer’s mask to the newly created shapelayer:
To create the border layer, the same path will be used. The only difference is that the border shape will have a transparent fillColor and a white strokeColor.
CAShapeLayer *shape = [CAShapeLayer layer];
shape.frame = self.bounds;
shape.path = path;
shape.lineWidth = 3.0f;
shape.strokeColor = [UIColor whiteColor].CGColor;
shape.fillColor = [UIColor clearColor].CGColor;
[self.layer insertSublayer: shape atIndex:0];
var shape = CAShapeLayer()
shape.frame = self.bounds
shape.path = path
shape.lineWidth = 3.0
shape.strokeColor = UIColor.whiteColor().CGColor
shape.fillColor = UIColor.clearColor().CGColor
self.layer.insertSublayer(shape, atIndex: 0)
And the full source code is here:
Tested with Xcode 6 beta 6.