After finding this answer (thanks for the kickstart) and experimenting with the missing details, here is my final understanding:
- a layer needs to be created only once
- it should be updated when the view rectangle changes
- best place to grab that is in layoutSubviews ()
We can use the ability to have our own layer shape class for the UIView to encapsulate this a bit. So first, we define our own layer class using the CAShapeLayer mask:
class RoundedShapeLayer: CAShapeLayer { override init() { super.init() self.mask = CAShapeLayer() } override init(layer: Any) { super.init(layer: layer) self.mask = CAShapeLayer() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) self.mask = CAShapeLayer() } func update(for bounds: CGRect) { (mask as! CAShapeLayer).path = UIBezierPath(roundedRect: bounds, byRoundingCorners: [UIRectCorner.topRight, UIRectCorner.topLeft], cornerRadii: CGSize(width: 10, height: 10)).cgPath } }
Then we can use it in a UIView:
@IBDesignable class RoundedCornerView: UIView { override class var layerClass: AnyClass { get { return RoundedShapeLayer.self } } override init(frame: CGRect) { super.init(frame: frame) } required init?(coder: NSCoder) { super.init(coder: coder) } override func layoutSubviews() { super.layoutSubviews() (layer as! RoundedShapeLayer).update(for: bounds) } }
There is more work to make the angles customizable, but what a spirit.
source share