斯威夫特:按钮圆角打破约束

我有一个通过xib加载自定义单元格的tableview,在那个单元格中我有状态按钮,右下角应该是圆形的。 按钮具有约束尾随/前导/底部空间到superview = 0和height = 30。

在此处输入图像描述

如果没有四舍五入,它就会完美地工作,只要我绕过一个角落,例如右下角,约束就会中断

self.btnStatus.roundCorners(corners: [.bottomRight], radius: 7.0, borderWidth: nil, borderColor: nil) 

在此处输入图像描述

这里的一些人建议调用layoutSubviews(),但它没有帮助我。

更具体地说,我创建了一个简单的项目,您可以在其中查看整个项目。

正确的链接

ButtonRoundCorner.zip

通过子类化按钮并通过覆盖其layoutSubviews()函数放置“舍入”代码,可以获得更可靠的结果。

首先,如果你想添加一个边框,你不想添加多个“边框子图层”…所以将你的UIView扩展名更改为:

 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); } } } 

接下来,添加一个UIButton子类:

 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) } } 

这给您带来了一些好处:1)当按钮框改变时(例如,旋转设备),它将更新其遮罩层框架; 2)您可以从自定义单元格类 cellForRowAt设置这些值。

无论哪种方式,将您的btnStatus类从UIButton更改为RoundedButton – 在故事板和@IBOutlet连接中都是如此。

然后将CustomTableViewCell更改为:

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

最后,您的cellForRowAt函数变为:

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = self.tableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath) as! CustomTableViewCell return cell } 

应该这样做……

我查看了你的代码。 问题是你的roundCorners函数取决于你的视图设置图层属性的界限,你在awakeFromNib中调用roundCorners ,此时你的单元格与NIB文件中的边界相同,因为尚未计算autolayout。 您需要将roundCorners调用移动到layoutSubviews ,以便在自动布局完成后计算您的边界。

 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) } } 

编辑还将cell.setNeedsLayout()添加到cellforRowAt以强制在第一次绘制单元格之前调用layoutSubviews。

也许你的按钮是重叠的,因为它没有上限? 尝试添加明亮边框,看看是否可以看到顶部,如果没有尝试在顶部添加约束。 另外,不要给它一个静态高度,而是尝试使它与其上方的物体成比例高度(可能是设备的屏幕尺寸导致它重叠)