Я бы посоветовал:
- добавить свой подслой в
init
(чтобы он добавлялся один и только один раз); - настроить его
frame
и path
вlayoutSubviews
(поэтому, если размер изменен, будь то из-за ограничений или другого механизма, слой будет обновляться соответствующим образом); - при добавлении подпредставления / подслоя, размеры которого основаны на размере текущего представления, используйте ссылку
bounds
(система координат в текущем представлении), а не frame
и center
(оба из которых находятся в системе координат суперпредставления);и - либо используют
addSublayer
подход или layerClass
подход, но не оба.
Таким образом, добавляя CAShapeLayer
в качестве подслоя:
@IBDesignable
class CircleView: UIView {
@IBInspectable var bubbleColor: UIColor = .blue { didSet { shapeLayer.fillColor = bubbleColor.cgColor } }
private lazy var shapeLayer: CAShapeLayer = {
let sLayer = CAShapeLayer()
sLayer.fillColor = bubbleColor.cgColor
return sLayer
}()
override init(frame: CGRect = .zero) {
super.init(frame: frame)
configure()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
configure()
}
override func layoutSubviews() {
super.layoutSubviews()
shapeLayer.frame = bounds
updatePath()
}
}
// MARK: - Utility methods
private extension CircleView {
func configure() {
layer.addSublayer(shapeLayer)
}
func updatePath() {
let diameter = min(bounds.width, bounds.height)
let arcCenter = CGPoint(x: bounds.midX, y: bounds.midY)
shapeLayer.path = UIBezierPath(arcCenter: arcCenter, radius: diameter / 2, startAngle: 0, endAngle: .pi * 2, clockwise: true).cgPath
}
}
Выход:
![enter image description here](https://i.stack.imgur.com/1Dy18.png)
Или, если вы хотите использовать layerClass
подход:
@IBDesignable
class CircleView: UIView {
@IBInspectable var bubbleColor: UIColor = .blue { didSet { shapeLayer.fillColor = bubbleColor.cgColor } }
override class var layerClass: AnyClass { return CAShapeLayer.self }
private var shapeLayer: CAShapeLayer { return layer as! CAShapeLayer}
override init(frame: CGRect = .zero) {
super.init(frame: frame)
configure()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
configure()
}
override func layoutSubviews() {
super.layoutSubviews()
updatePath()
}
}
// MARK: - Utility methods
private extension CircleView {
func configure() {
shapeLayer.fillColor = bubbleColor.cgColor
}
func updatePath() {
let diameter = min(bounds.width, bounds.height)
let arcCenter = CGPoint(x: bounds.midX, y: bounds.midY)
shapeLayer.path = UIBezierPath(arcCenter: arcCenter, radius: diameter / 2, startAngle: 0, endAngle: .pi * 2, clockwise: true).cgPath
}
}