Isuru
Isuru

Reputation: 31283

CAShapeLayer with UIBezierPath

I wanted to display a triangle shaped view in a UITableView cell like this.

enter image description here

I managed to accomplish this using the blow code.

import UIKit

class TriangleView: UIView {

    override func drawRect(rect: CGRect) {
        let width = self.layer.frame.width
        let height = self.layer.frame.height

        let path = CGPathCreateMutable()
        CGPathMoveToPoint(path, nil, 0, 0)
        CGPathAddLineToPoint(path, nil, width, 0)
        CGPathAddLineToPoint(path, nil, 0, height)
        CGPathAddLineToPoint(path, nil, 0, 0)
        CGPathCloseSubpath(path)

        let mask = CAShapeLayer()
        mask.frame = self.layer.bounds
        mask.path = path

        self.layer.mask = mask

        let shape = CAShapeLayer()
        shape.frame = self.bounds
        shape.path = path
        shape.fillColor = UIColor.clearColor().CGColor

        self.layer.insertSublayer(shape, atIndex: 0)
    }
}

While I was searching how to create shapes in UIViews, I discovered that you could use UIBezierPath to do the same. So I tried replicating the same thing using UIBezierPath.

let path = UIBezierPath()
path.moveToPoint(CGPoint(x: 0, y: 0))
path.moveToPoint(CGPoint(x: width, y: 0))
path.moveToPoint(CGPoint(x: 0, y: height))
path.moveToPoint(CGPoint(x: 0, y: 0))
path.closePath()

let mask = CAShapeLayer()
mask.frame = self.bounds
mask.path = path.CGPath

self.layer.mask = mask

let shape = CAShapeLayer()
shape.frame = self.bounds
shape.path = path.CGPath
shape.fillColor = UIColor.clearColor().CGColor

self.layer.insertSublayer(shape, atIndex: 0)

But this simply does't work. No shape is getting displayed.

Do I need to do anything extra in order to get this working?

Upvotes: 5

Views: 9384

Answers (2)

chiahao
chiahao

Reputation: 166

The problem should be the mask on layer and the color of shape.
The following code work for me.

class TriangleView: UIView {
    override func drawRect(rect: CGRect) {
        let width:CGFloat = bounds.width/9
        let height:CGFloat = bounds.width/9

        let path = UIBezierPath()
        path.moveToPoint(bounds.origin)
        path.addLineToPoint(CGPoint(x: width, y: bounds.origin.y))
        path.addLineToPoint(CGPoint(x: bounds.origin.x, y: height))
        // closePath will connect back to start point
        path.closePath()

        let shape = CAShapeLayer()
        shape.path = path.CGPath
        shape.fillColor = UIColor.blueColor().CGColor

        self.layer.insertSublayer(shape, atIndex: 0)

        // Setting text margin
        textContainerInset = UIEdgeInsetsMake(8, width, 8, 0)
    }
}

Upvotes: 3

rdelmar
rdelmar

Reputation: 104082

You're making this harder than it needs to be. You only need to add a shape layer with a path, and set the fillColor of that layer. The main reason your code doesn't work though, is because you're using moveToPoint for all you lines instead of addLineToPoint for all but the first one.

class TriangleView: UIView {

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

    override init(frame: CGRect) {
        super.init(frame: frame)
        let path = UIBezierPath()
        path.moveToPoint(CGPoint(x: 0, y: 0))
        path.addLineToPoint(CGPoint(x: frame.size.width, y: 0))
        path.addLineToPoint(CGPoint(x: 0, y: frame.size.height))
        path.closePath()

        let shape = CAShapeLayer()
        shape.frame = self.bounds
        shape.path = path.CGPath
        shape.fillColor = UIColor.blueColor().CGColor
        self.layer.addSublayer(shape)
    }
}

Upvotes: 9

Related Questions