2

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

Md. Ibrahim Hassan
  • 5,359
  • 1
  • 25
  • 45
sarunw
  • 8,036
  • 11
  • 48
  • 84
  • Check the `contentScale` if your layer (after it has been assigned to the view). It might not be properly set to 2.0 for retina displays. If so, the layer's coordinate will be interpreted as physical pixels instead of logical points. – Codo Nov 07 '16 at 12:32

1 Answers1

1

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 coordinates 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

Jeyamahesan
  • 1,101
  • 7
  • 15
  • It work thanks! Can you explain a little bit about the problem? I assume frame is zero right since I didn't set it, but why it show as 1/4 rectangle like that. – sarunw Nov 08 '16 at 04:06
  • And result view is still upside down (path look correct) but when apply mask it turn upside down. Is it normal? What is the proper way to handle this? – sarunw Nov 08 '16 at 04:18
  • @sarunw Please check the updated answer and check this SO to know about the difference between the frame and bounds. http://stackoverflow.com/questions/1210047/cocoa-whats-the-difference-between-the-frame-and-the-bounds – Jeyamahesan Nov 08 '16 at 07:03