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 添加阴影
将自定义参数传递给 uibutton #selector swift 3