Currently, I implement multiple corner radii on my bubbleView
which is a UIView
by doing something along the lines of:
// First create the bubble view
bubbleView = UIView()
bubbleView.layer.cornerRadius = 4 // set the corner radius of the "smaller" corner style
bubbleView.layer.cornerCurve = .continuous
bubbleView.clipsToBounds = true
bubbleView.backgroundColor = UIColor.systemBlue
// ...
// Update the "mask" of the bubble view to give another type of rounded corners
let maskPath = UIBezierPath(roundedRect:bubbleView.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: 17.0, height: 0.0))
let maskLayer = CAShapeLayer()
maskLayer.path = maskPath.cgPath
bubbleView.layer.mask = maskLayer // updates the mask
My issue is I am setting the mask, self.bubbleView.layer.mask = maskLayer
, of the bubbleView
in the func layoutSubviews()
function, which causes a noticable delay, for example, when the device rotates from portrait to landscape mode.
Is there a faster, more efficient way to implement different corner radii for a UIView
that responds faster than simply updating the mask in layoutSubviews()
?
You could try using a subview with the larger radius corners...
Here's some sample code:
class MyCustomView: UIView {
// self's background will be .clear
// so we use a custom property to set the
// background of the subView
public var viewColor: UIColor = .clear {
didSet {
subView.backgroundColor = viewColor
}
}
// corners to use larger radius
public var corners: CACornerMask = [] {
didSet {
subView.layer.maskedCorners = corners
}
}
public var smallRadius: CGFloat = 0 {
didSet {
layer.cornerRadius = smallRadius
}
}
public var bigRadius: CGFloat = 0 {
didSet {
subView.layer.cornerRadius = bigRadius
}
}
private let subView = UIView()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
addSubview(subView)
subView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
subView.topAnchor.constraint(equalTo: topAnchor),
subView.leadingAnchor.constraint(equalTo: leadingAnchor),
subView.trailingAnchor.constraint(equalTo: trailingAnchor),
subView.bottomAnchor.constraint(equalTo: bottomAnchor),
])
// round all 4 corners of self's layer with the small radius
layer.masksToBounds = true
layer.cornerRadius = smallRadius
layer.cornerCurve = .continuous
// subview only specified corners with bigger radius
subView.layer.masksToBounds = true
subView.layer.cornerRadius = bigRadius
subView.layer.cornerCurve = .continuous
subView.layer.maskedCorners = corners
}
}
and a test view controller to demo it:
class TestViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let v = MyCustomView()
v.viewColor = .systemBlue
v.smallRadius = 4
v.bigRadius = 17
// set top-left, top-right, bottom-left to use larger radius
v.corners = [.layerMinXMinYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner]
v.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(v)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
v.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 60.0),
v.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -60.0),
v.heightAnchor.constraint(equalToConstant: 120.0),
v.centerYAnchor.constraint(equalTo: g.centerYAnchor),
])
}
}