Swift:按钮圆角打破约束

Posted

技术标签:

【中文标题】Swift:按钮圆角打破约束【英文标题】:Swift: Button round corner breaks contraints 【发布时间】:2017-11-27 16:42:49 【问题描述】:

我有一个表格视图,其中包含通过 xib 加载的自定义单元格,在该单元格中我有状态按钮,右下角应该是圆角的。该按钮的尾随/前导/底部空间限制为 superview=0 和 height=30。

如果不四舍五入,它就可以完美地工作,只要我将一个角(例如右下角)转角,约束就会中断

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

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

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

正确链接

ButtonRoundCorner.zip

【问题讨论】:

关于打破约束的错误是什么? 无需查看您的代码,如果它违反了约束,只需将其放在 UIView 中,并为该容器 UIView 提供约束。约束不会关心视图内部的内容,圆角与否。 @benjiiiii:完全没有错误,只是按钮没有对齐... @mihatel - 您的“保管箱”链接错误...您必须选择“分享”然后创建一个链接。 @mihatel - 看看我的回答。我想你会发现它是一种更可靠的方法。 【参考方案1】:

您可以通过将按钮子类化并通过覆盖其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

应该可以的...

【讨论】:

像魅力一样工作!【参考方案2】:

我查看了您的代码。问题是您的roundCorners 函数取决于您的视图边界来设置图层的属性,并且您在awakeFromNib 中调用roundCorners,此时您的单元格具有与NIB 文件中相同的边界,因为自动布局尚未还算算。您需要将您的 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)
    

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

【讨论】:

同样的问题 :( 我正在运行它并且它正在工作。您是否正确移动了代码? 是的,哪个模拟器,我在iphone7,ios11中检查,如果你能上传zip就好了,我就跑比较一下 它在 iphone 7 iOS11 上是正确的。查看整个文件的编辑答案。 在真实设备上也是如此,实际上如果我滚动它可以解决问题,但前提是再次渲染单元格【参考方案3】:

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

【讨论】:

dropbox.com/sh/751wo3hsesjxj6l/AAA3oJyPSVFQ3PZcvRTRPE-Sa?dl=0 没有帮助

以上是关于Swift:按钮圆角打破约束的主要内容,如果未能解决你的问题,请参考以下文章

Swift 3 - 自定义 UIButton 半径删除约束?

使用约束约束时按钮的角不保持圆角

swift 自定义view VFL 设置约束冲突

UIStackView中的圆形按钮(iOS Swift)

swift – 具有圆角和背景颜色的NSButton

Swift - 圆角半径和阴影问题