Reputation: 479
The two adjacent rectangle is ok as image below.
override func draw(_ rect: CGRect) {
// Drawing code
let leftTop = CGPoint(x:50,y:50)
let rightTop = CGPoint(x:150,y:100)
let leftMiddle = CGPoint(x:50,y:300)
let rightMiddle = CGPoint(x:150,y:300)
let leftDown = CGPoint(x:50,y:600)
let rightDown = CGPoint(x:150,y:650)
let context = UIGraphicsGetCurrentContext()
context?.addLines(between: [leftTop,rightTop,rightMiddle,leftMiddle])
UIColor.black.setFill()
context?.fillPath()
context?.addLines(between: [leftMiddle,rightMiddle,rightDown,leftDown])
context?.fillPath()
let leftTop1 = CGPoint(x:200,y:50)
let rightTop1 = CGPoint(x:300,y:100)
let leftMiddle1 = CGPoint(x:200,y:300)
let rightMiddle1 = CGPoint(x:300,y:350)
let leftDown1 = CGPoint(x:200,y:600)
let rightDown1 = CGPoint(x:300,y:650)
context?.addLines(between: [leftTop1,rightTop1,rightMiddle1,leftMiddle1])
UIColor.black.setFill()
context?.fillPath()
context?.addLines(between: [leftMiddle1,rightMiddle1,rightDown1,leftDown1])
context?.fillPath()
}
You may need to zoom in to see the gap. If I draw a thin line to cover the gap, then any width may overlap if the color has an alpha channel.
Change shapeColor to let shapeColor = UIColor(white: 0.0, alpha: 0.5)
and add context?.setShouldAntialias(false)
Upvotes: 4
Views: 297
Reputation: 196
This is related to screen resolution. On devices with high resolution one point actually has 2 or 3 pixels. That's why to draw an inclined line iOS draws some edge pixels with some opacity, when 2 lines are next to each other these edge pixels overlap. In your case I was able to fix the issue by making the following change
let leftTop1 = CGPoint(x:200,y:50)
let rightTop1 = CGPoint(x:300,y:100)
let leftMiddle1 = CGPoint(x:200,y:300)
let rightMiddle1 = CGPoint(x:300,y:350)
let leftMiddle2 = CGPoint(x:200,y:300.333)
let rightMiddle2 = CGPoint(x:300,y:350.333)
let leftDown1 = CGPoint(x:200,y:600)
let rightDown1 = CGPoint(x:300,y:650)
context?.addLines(between: [leftTop1,rightTop1,rightMiddle1,leftMiddle1])
UIColor.black.setFill()
context?.fillPath()
context?.addLines(between: [leftMiddle2,rightMiddle2,rightDown1,leftDown1])
context?.fillPath()
Basically moving down the second rhomboid by 1 pixel (1/3 = 0.333...), I have tested on a screen with 1:3 pixel density, for the solution to work on all devices you'll need to check the scaleFactor of the screen.
Upvotes: 1
Reputation: 2349
I have the same result using the CGContext even if I use setShouldAntialias(true)
or if I try to call strokePath() on the context. But it works fine with sublayers
, CGPath
and strokeColor
class RhombView: UIView {
let shapeColor: UIColor = .black
override init(frame: CGRect) {
super.init(frame: frame)
self.setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setupView()
}
func setupView() {
let leftTop1 = CGPoint(x:200.0,y:50.0)
let rightTop1 = CGPoint(x:300.0,y:100.0)
let leftMiddle1 = CGPoint(x:200.0,y:300.0)
let rightMiddle1 = CGPoint(x:300.0,y:350.0)
let leftDown1 = CGPoint(x:200.0,y:600.0)
let rightDown1 = CGPoint(x:300.0,y:650.0)
var path = UIBezierPath()
path.move(to: leftTop1)
path.addLine(to: rightTop1)
path.addLine(to: rightMiddle1)
path.addLine(to: leftMiddle1)
path.close()
let subLayer1 = CAShapeLayer()
subLayer1.path = path.cgPath
subLayer1.frame = self.layer.frame
subLayer1.fillColor = shapeColor.cgColor
subLayer1.strokeColor = shapeColor.cgColor
self.layer.addSublayer(subLayer1)
path = UIBezierPath()
path.move(to: leftMiddle1)
path.addLine(to: rightMiddle1)
path.addLine(to: rightDown1)
path.addLine(to: leftDown1)
path.close()
let subLayer2 = CAShapeLayer()
subLayer2.path = path.cgPath
subLayer2.frame = self.layer.frame
subLayer2.fillColor = shapeColor.cgColor
subLayer2.strokeColor = shapeColor.cgColor
self.layer.addSublayer(subLayer2)
self.layer.backgroundColor = UIColor.white.cgColor
}
}
If you remove both subLayer.strokeColor
you will see the gap.
Upvotes: 3