Reputation: 4947
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):
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?
Upvotes: 4
Views: 442
Reputation: 4836
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.
Upvotes: 6
Reputation: 5216
Yes as per the doc it should be a rect but I dont think it mentions the lineWidth
This seems to be the reason why you see a pixel missing
borderLayer.lineWidth = 2
Now when you change the width to 1 then it draws a perfect rectangle without any missing pixels
Changing the lineWidth to 10 shows considerable difference in the gap
The solution to your problem would be using this
borderLayer.lineCap = kCALineCapSquare
Check these lineCap & Line Cap Values
Upvotes: 2
Reputation: 5563
The reason you're seeing a missing pixel on your rect is because you haven't configured the lineCap
property correctly.
Try adding this line :
borderLayer.lineCap = kCALineCapSquare
For more on line cap (and line join which is also important to understand) see this page : http://calayer.com/core-animation/2016/05/22/cashapelayer-in-depth.html#line-cap
Upvotes: 2