sarunw sarunw - 28 days ago 16
Swift Question

CAShaperLayer as mask show only 1/4 of UIView

I try to make

UIView
to show zig-zag bottom edge. Something like http://www.shutterstock.com/pic-373176370/stock-vector-receipt-vector-icon-invoice-flat-illustration-cheque-shadow-bill-with-total-cost-amount-and-dollar-symbol-abstract-text-receipt-paper-isolated-on-green.html?src=zMGBKj_5etMCcRB3cKmCoA-1-2

I have method that create a path and set as mask, but it show as 1/4 of the view. Do I need to set something else? Look like a retina problem or coordinate problem, but don't sure which one.

func layoutZigZag(bounds: CGRect) -> CALayer {
let maskLayer = CAShapeLayer()
maskLayer.bounds = bounds
let path = UIBezierPath()

let width = bounds.size.width
let height = bounds.size.height

let topRight = CGPoint(x: width , y: height)
let topLeft = CGPoint(x: 0 , y: height)
let bottomRight = CGPoint(x: width , y: 0)
let bottomLeft = CGPoint(x: 0 , y: 0)

let zigzagHeight: CGFloat = 10
let numberOfZigZag = Int(floor(width / 23.0))
let zigzagWidth = width / CGFloat(numberOfZigZag)

path.move(to: topLeft)
path.addLine(to: bottomLeft)

// zigzag
var currentX = bottomLeft.x
var currentY = bottomLeft.y
for i in 0..<numberOfZigZag {
let upper = CGPoint(x: currentX + zigzagWidth / 2, y: currentY + zigzagHeight)
let lower = CGPoint(x: currentX + zigzagWidth, y: currentY)

path.addLine(to: upper)
path.addLine(to: lower)

currentX += zigzagWidth
}

path.addLine(to: topRight)
path.close()

maskLayer.path = path.cgPath
return maskLayer
}

and

let rect = CGRect(x: 0, y: 0, width: 320, height: 400)
let view = UIView(frame: rect)
view.backgroundColor = UIColor.red
let zigzag = layoutZigZag(bounds: rect)
view.layer.mask = zigzag


Path look correct

Path look correct

Result is 1/4 of the view

Result

Answer

Change maskLayer.bounds = bounds to maskLayer.frame = bounds

Update:

Upside down is because of difference between the UI and CG, we are creating the path in UIBezierPath and converting that path as a CGPath (maskLayer.path = path.cgPath). First we have to know the difference, where CGPath is Quartz 2D and origin is at the bottom left while in UIBezierPath is UIKit origin is at the top-left. As per your code, applied frames are as per the top-left ie UIBezierPath when we transform to CGPath (origin at bottom left) it becomes upside down. so change the code as below to get the desired effect.

    let topRight = CGPoint(x: width , y: 0)
    let topLeft = CGPoint(x: 0 , y: 0)
    let bottomLeft = CGPoint(x: 0 , y: (height - zigzagHeight))

Quartz 2D Coordinate Systems

enter image description here

UIBezierPath Coordinate Systems

enter image description here