I have a tableview with custom cell loaded via xib and in that cell I have status button which bottom right corner should be rounded. The button has constraints Trailing/Leading/Bottom space to superview=0 and height=30.
Without rounding it is working perfectly, as soon as I round one corner for example bottom right the constraints breaks
self.btnStatus.roundCorners(corners: [.bottomRight], radius: 7.0, borderWidth: nil, borderColor: nil)
Some guys here suggesting to call layoutSubviews() but it didn't helped me.
To be more specific I've created simple project where you can have a look into whole project.
Correct Link
You can get more reliable results by subclassing your button and placing your "rounding" code by overriding its layoutSubviews()
function.
First, if you want to add a border, you don't want to add multiple "border sublayers" ... so change your UIView
extension to this:
extension UIView {
func roundCorners(corners: UIRectCorner, radius: CGFloat, borderWidth: CGFloat?, borderColor: UIColor?) {
let maskPath = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let maskLayer = CAShapeLayer()
maskLayer.frame = self.bounds
maskLayer.path = maskPath.cgPath
self.layer.mask = maskLayer
self.layer.masksToBounds = true
if (borderWidth != nil && borderColor != nil) {
// remove previously added border layer
for layer in layer.sublayers! {
if layer.name == "borderLayer" {
layer.removeFromSuperlayer()
}
}
let borderLayer = CAShapeLayer()
borderLayer.frame = self.bounds;
borderLayer.path = maskPath.cgPath;
borderLayer.lineWidth = borderWidth ?? 0;
borderLayer.strokeColor = borderColor?.cgColor;
borderLayer.fillColor = UIColor.clear.cgColor;
borderLayer.name = "borderLayer"
self.layer.addSublayer(borderLayer);
}
}
}
Next, add a UIButton
subclass:
class RoundedButton: UIButton {
var corners: UIRectCorner?
var radius = CGFloat(0.0)
var borderWidth = CGFloat(0.0)
var borderColor: UIColor?
override func layoutSubviews() {
super.layoutSubviews()
// don't apply mask if corners is not set, or if radius is Zero
guard let _corners = corners, radius > 0.0 else {
return
}
roundCorners(corners: _corners, radius: radius, borderWidth: borderWidth, borderColor: borderColor)
}
}
This gives you a couple benefits: 1) It will update its mask layer frame when the button frame changes (rotating the device, for example), and 2) you could set these values either from your custom cell class or from cellForRowAt.
Either way, change your btnStatus
class from UIButton
to RoundedButton
- both in your storyboard and the @IBOutlet
connection.
Then change your CustomTableViewCell
to this:
class CustomTableViewCell: UITableViewCell {
@IBOutlet weak var btnStatus: RoundedButton!
override func awakeFromNib() {
super.awakeFromNib()
// set up corner maskign
btnStatus.corners = .bottomRight
btnStatus.radius = 7.0
// set if desired
// btnStatus.borderWidth = 2.0
// btnStatus.borderColor = .blue
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
And finally, your cellForRowAt
function becomes:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath) as! CustomTableViewCell
return cell
}
That should do it...