Swift: Button round corner breaks contraints

前端 未结 3 789
一整个雨季
一整个雨季 2020-12-22 10:21

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/Lea

相关标签:
3条回答
  • 2020-12-22 11:10

    I looked at your code. The problem is that your roundCorners function is depending on your view's bounds to set your layer's properties and you are calling roundCorners in awakeFromNib at which point your cell has the same bounds as in the NIB file because autolayout has not been calculated yet. You need to move your roundCorners call into layoutSubviews, so it gets called after autolayout is done computing your bounds.

    import UIKit
    
    class CustomTableViewCell: UITableViewCell {
    
        @IBOutlet weak var btnStatus: UIButton!    
        override func layoutSubviews() {
            super.layoutSubviews()
                    self.btnStatus.roundCorners(corners: [.bottomRight], radius: 7.0, borderWidth: nil, borderColor: nil)
        }
    }
    

    EDIT also add cell.setNeedsLayout() to cellforRowAt to force layoutSubviews to be called before the cell is drawn for the first time.

    0 讨论(0)
  • 2020-12-22 11:11

    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...

    0 讨论(0)
  • 2020-12-22 11:16

    Maybe your button is overlapping since it doesn't have an upper constraint? Try adding a bright border and see if you can see the top part, if not try adding a constraint to the top. Also, instead of giving it a static height, try making it a proportional height to the object above it (maybe the screen size of your device is causing it to overlap)

    0 讨论(0)
提交回复
热议问题