CAShapeLayer with UIBezierPath
Asked Answered
F

2

5

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?

Failsafe answered 6/4, 2015 at 17:49 Comment(1)
You have to create a new context to draw.Russo
C
9

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)
    }
}
Casi answered 6/4, 2015 at 20:16 Comment(3)
Can the second layer be replaced with a simple self.backgroundColor = UIColor.blueColor()?Back
Sorry, my mistake - I thought that like the OP you were adding a mask and inserting an identical sublayer, when a mask and backgroundColor would sufficeBack
How can I use a gradient color rather a simple color as shapes fillcolor @CasiTita
M
3

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)
    }
}
Malaria answered 17/3, 2016 at 14:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.