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

Posted

技术标签:

【中文标题】Swift 3 - 自定义 UIButton 半径删除约束?【英文标题】:Swift 3 - Custom UIButton radius deletes constraints? 【发布时间】:2017-01-17 11:08:55 【问题描述】:

我的视图控制器拥有一个带有 3 个按钮的堆栈视图。一个固定在中心,宽度固定,stackview 设置为按比例填充,这样其他两个按钮将是对称的。

不过,我也在自定义按钮的圆角半径,一旦应用程序加载按钮,就会以不希望的方式调整大小。

我尝试了许多 stackview 分布和填充设置。从 stackview 中删除按钮并简单地尝试将它们限制在普通 UIView 上的边缘似乎无济于事,但不确定约束是否被删除。

在视觉上,按钮将位于屏幕的右下角,边缘和按钮之间的空间为 0。目前,它的布局方式在多个设备上似乎没有限制,导致它在较大的显示器上拥有空间,并在模拟器内的小显示器上退出屏幕。

尝试编码以圆所需的角落:

@IBOutlet fileprivate weak var button: UIButton!  didSet 
    button.round(corners: [.topRight, .bottomLeft], radius: 50 , borderColor: UIColor.blue, borderWidth: 5.0)
    button.setNeedsUpdateConstraints()
    button.setNeedsLayout()
 

override func viewDidLayoutSubviews() 
   button.layoutIfNeeded()


ovverride func updateViewContraints() 
    button.updateConstraintsIfNeeded()
    super.updateViewConstraints()

可以在此处找到正在使用的 UIView 扩展: https://***.com/a/35621736/5434541

什么解决方案可用于正确调整按钮角半径'并允许约束将按钮更新为应有的状态。

【问题讨论】:

这两种方法的行为是否相同? @Ben 是的,我在尝试所有方法时都得到了相同的行为。目前这是在模拟器中发生的,在 iPhone 5 上进行了测试,它似乎可以按照我的意愿运行,但是这种意外行为让我担心不知道它是否会发生在其他设备上。同样,一旦我实现了这些方法,应用程序当前就会滞后很多!我知道这与特定问题无关,但很好奇 viewDidlayout 子视图是否应该在另一个线程上执行?谢谢! 【参考方案1】:

没有看到你的完整代码,我怀疑你得到了这个,因为它用边框绘制了多个图层,并且从不删除任何图层!如果按钮调整大小,旧图层仍然存在。这是一个片段,显示在重绘时删除旧图层,您应该能够适应。我在堆栈视图中对此进行了测试,它在旋转时也表现正确:

class RoundedCorner: UIButton 

    var lastBorderLayer:CAShapeLayer?
    override func layoutSubviews()  setup() 

    func setup() 
        let r = self.bounds.size.height / 2
        let path = UIBezierPath(roundedRect: self.bounds,
                                byRoundingCorners: [.topLeft, .bottomRight],
                                cornerRadii: CGSize(width: r, height: r))
        let mask = CAShapeLayer()
        mask.path = path.cgPath
        addBorder(mask: mask, borderColor: UIColor.blue, borderWidth: 5)
        self.layer.mask = mask
    

    func addBorder(mask: CAShapeLayer, borderColor: UIColor, borderWidth: CGFloat) 
        let borderLayer = CAShapeLayer()
        borderLayer.path = mask.path
        borderLayer.fillColor = UIColor.clear.cgColor
        borderLayer.strokeColor = borderColor.cgColor
        borderLayer.lineWidth = borderWidth
        borderLayer.frame = bounds
        if let last = self.lastBorderLayer, let index = layer.sublayers?.index(of: last) 
            layer.sublayers?.remove(at: index)
        
        layer.addSublayer(borderLayer)
        self.lastBorderLayer = borderLayer
    

您还在评论中提到了应用滞后。我并不感到惊讶,因为每次更新都会多次调用布局,并且您每次都在创建一个新层。您可以通过保存底部框架的最后尺寸并进行比较来避免这种情况。如果相同,请不要重新创建图层。

【讨论】:

所以我打算实现你的 RoundedCorner 类,但在阅读了你的代码后,我觉得我在最初的问题中可能做错了什么。因此,我尝试进行更多研究并编辑了上面的问题以更新发现。我非常感谢您的帮助,因为您的回答将我引向正确的方向。 不确定你编辑了什么,你能分享整个按钮类吗? 按钮只是一个连接到视图控制器的故事板按钮。没有为其创建自定义子类按钮。应用程序运行,一旦按钮被设置,didSet 就会调用round() 方法,然后在setNeeds() 方法之后告诉控制器在调用viewDidUpdateLayoutSubviews() 时更新布局。我相信事情就是这样发展的。 该方法仍然存在我指出的原始问题。每次重绘按钮时,您都在添加另一个子图层。您必须先清除旧图层(就像我的示例使用 layer.sublayers?.remove 一样)。这就是为什么您会看到多个圆角。

以上是关于Swift 3 - 自定义 UIButton 半径删除约束?的主要内容,如果未能解决你的问题,请参考以下文章

使用 UIBezierPath 将半径设置为某些角并向自定义 UIButton 添加阴影

Swift:以编程方式在键盘上方添加 UIButton

将自定义参数传递给 uibutton #selector swift 3

Swift:UIButton 自定义

通过扩展 UIButton 类使用 Swift 创建自定义按钮

更改自定义 UIButton 的 TitleColor (iOS 8 + swift)