I'm trying to draw: O-O-O in the midY of UIView but get:
Here is a func for calculating position for CAShapeLayer.frame. Even indices are dots and odd indices are lines. Number of lines is always minus one number of dots.
func frameForShape(at index: Int) -> CGRect {
let dotWidth = dotRadius * 2
let lineWidth = (view.bounds.width - (CGFloat(numberOfDots) * dotWidth)) / CGFloat(numberOfLines)
if index % 2 == 0 {
let count = CGFloat(index) / 2
let x = (lineWidth * count) + (dotWidth * count)
return CGRect(x: x, y: 0, width: dotWidth, height: view.bounds.height)
} else {
let count = Double(index) / 2
let x = (lineWidth * CGFloat(floor(count))) + (dotWidth * CGFloat(ceil(count)))
return CGRect(x: x, y: 0, width: lineWidth, height: view.bounds.height)
}
}
func setFrame() {
for (index, shape) in shapes.enumerated() {
shape.frame = frameForShape(at: index)
}
}
frameForShape(at:) correctly return frame position and size
This funcs draw a path in the center of given frame
func linePath(rect: CGRect) -> UIBezierPath {
let newRect = CGRect(x: rect.minX, y: rect.midY - (lineHeight / 2), width: rect.width, height: lineHeight)
let path = UIBezierPath(rect: newRect)
return path
}
func dotPath(rect: CGRect) -> UIBezierPath {
let newRect = CGRect(x: rect.midX - dotRadius, y: rect.midY - dotRadius, width: dotRadius * 2, height: dotRadius * 2)
let path = UIBezierPath(ovalIn: newRect)
return path
}
Here, I'm adding CAShapeLayers to yellow UIView
override func awakeFromNib() {
super.awakeFromNib()
for shape in shapes {
view.layer.addSublayer(shape)
}
}
override func layoutSubviews() {
super.layoutSubviews()
layoutIfNeeded()
setFrame()
build()
}
func build() {
for (index, shape) in shapes.enumerated() {
if index % 2 == 0 {
shape.path = dotPath(rect: shape.frame).cgPath
} else {
shape.path = linePath(rect: shape.frame).cgPath
}
}
}
Frames are correct so why dots and lines are misplaced?
I found this answer: https://stackoverflow.com/a/40194019/
incorrect position of your layer - frame should be equal to bounds of parent layer in parentView
But how draw path at specific position if UIBezierPath(ovalIn:) and UIBezierPath(rect:) draw all inside frame?
As the answer says, simply change shape.frame to shape.bounds in your call to build().
Remember that the coordinates of your shape layer are relative to the containing view, so bounds needs to be used.