Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CAShapeLayer missing pixel in top-left corner

I'm using a CAShapeLayer with a UIBezierPath to draw a bordered box in a view.

This is working fine, but the very first pixel (top, left) is not drawn.

This is my code:

let focusSize = CGRect(x: focusX, y: focusY, width: focusWidth, height: focusHeight)
let focusPath = UIBezierPath(roundedRect: focusSize, cornerRadius: 0)

let borderLayer = CAShapeLayer()
borderLayer.path = focusPath.cgPath
borderLayer.fillColor = UIColor.clear.cgColor
borderLayer.strokeColor = UIColor.white.cgColor
borderLayer.lineWidth = 2
borderLayer.frame = self.someView.bounds
self.someView.layer.addSublayer(borderLayer)

The result (note the pixel in the top, left corner):

Weird pixel

I thought this might be related to antialiasing, but playing around with the x, y and borderWidth does not seem to fix the issue. Does anyone know what is causing this?

like image 723
Rob Avatar asked Dec 24 '22 20:12

Rob


1 Answers

For some reason when you create a path using (roundedRect rect: CGRect, cornerRadius: CGFloat) it is not closed (despite what it says in the documentation).

Calling focusPath.close() closes the path and removes the missing pixel.

However, if you don't want rounded corners just use a normal rect and it will draw correctly.

let focusPath = UIBezierPath(rect: focusSize)

For anyone interested here are the resulting paths:

UIBezierPath(roundedRect:  CGRect(x: 10, y: 10, width: 100, height: 100), cornerRadius: 0)
<UIBezierPath: 0x6180000b8000; <MoveTo {10, 10}>,
 <LineTo {110, 10}>,
 <LineTo {110, 110}>,
 <LineTo {10, 110}>,
 <LineTo {10, 10}>,
 <LineTo {10, 10}>

//After calling path.close()
<UIBezierPath: 0x6180000b8000; <MoveTo {10, 10}>,
 <LineTo {110, 10}>,
 <LineTo {110, 110}>,
 <LineTo {10, 110}>,
 <LineTo {10, 10}>,
 <LineTo {10, 10}>,
 <Close>

 UIBezierPath(rect: CGRect(x: 10, y: 10, width: 100, height: 100))
<UIBezierPath: 0x6180000b7f40; <MoveTo {10, 10}>,
 <LineTo {110, 10}>,
 <LineTo {110, 110}>,
 <LineTo {10, 110}>,
 <Close>

Setting the lineCap may make the box appear correctly, but isn't fixing the issue as it just extends the visible end points and covers up the missing bit. Set borderLayer.lineJoin = kCALineJoinBevel to see why this can be a problem.

like image 117
James P Avatar answered Jan 11 '23 04:01

James P