Ios Swift:按钮的圆角打破了禁忌
我有一个通过xib加载自定义单元格的tableview,在该单元格中我有一个状态按钮,右下角应该是圆角。该按钮具有尾随/前导/底部空间到superview=0和高度=30的约束 如果不四舍五入,它就可以完美地工作,例如,只要我转过一个角(右下角),约束就会中断Ios Swift:按钮的圆角打破了禁忌,ios,swift,autolayout,rounded-corners,Ios,Swift,Autolayout,Rounded Corners,我有一个通过xib加载自定义单元格的tableview,在该单元格中我有一个状态按钮,右下角应该是圆角。该按钮具有尾随/前导/底部空间到superview=0和高度=30的约束 如果不四舍五入,它就可以完美地工作,例如,只要我转过一个角(右下角),约束就会中断 self.btnStatus.roundCorners(corners: [.bottomRight], radius: 7.0, borderWidth: nil, borderColor: nil) 这里有些人建议调用layou
self.btnStatus.roundCorners(corners: [.bottomRight], radius: 7.0, borderWidth: nil, borderColor: nil)
这里有些人建议调用layoutSubviews(),但这对我没有帮助
更具体地说,我创建了一个简单的项目,您可以在其中查看整个项目
正确链接
您的按钮可能重叠,因为它没有上限约束?尝试添加明亮的边框,看看是否可以看到顶部,如果看不到,请尝试向顶部添加约束。另外,与其给它一个静态高度,不如试着使它与上面的物体成比例的高度(可能是设备的屏幕大小导致它重叠)可能你的按钮重叠了,因为它没有上限约束?尝试添加明亮的边框,看看是否可以看到顶部,如果看不到,请尝试向顶部添加约束。另外,与其给它一个静态高度,不如试着使它与上面的物体成比例的高度(可能是设备的屏幕大小导致它重叠)我看了你的代码。问题是,
roundCorners
函数取决于视图的边界来设置图层的属性,并且您正在awakeFromNib
中调用roundCorners
,此时您的单元格与NIB文件中的边界相同,因为尚未计算自动布局。您需要将roundCorners
调用移动到中,以便在自动布局完成边界计算后调用它
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,以强制在第一次绘制单元格之前调用布局子视图。我查看了您的代码。问题是,
roundCorners
函数取决于视图的边界来设置图层的属性,并且您正在awakeFromNib
中调用roundCorners
,此时您的单元格与NIB文件中的边界相同,因为尚未计算自动布局。您需要将roundCorners
调用移动到中,以便在自动布局完成边界计算后调用它
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,以强制在第一次绘制单元格之前调用LayoutSubview。通过对按钮进行子类化,并通过覆盖其
LayoutSubview()
函数放置“舍入”代码,可以获得更可靠的结果
首先,如果你想添加一个边框,你不想添加多个“边框子层”。。。因此,将您的ui视图
扩展名更改为:
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设置这些值
无论采用哪种方式,都可以在故事板和@IBOutlet
连接中将btnStatus
类从UIButton
更改为RoundedButton
然后将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
}
这应该可以做到…通过对按钮进行子类化,并通过覆盖其
layoutSubviews()
函数放置“舍入”代码,可以获得更可靠的结果
首先,如果你想添加一个边框,你不想添加多个“边框子层”。。。因此,将您的ui视图
扩展名更改为:
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设置这些值
无论采用哪种方式,都可以在故事板和@IBOutlet
连接中将btnStatus
类从UIButton
更改为RoundedButton
然后将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
}
应该这样做了…关于打破约束给出了哪些错误?如果代码打破了约束,只需将其放在
UIView
中,并为该容器UIView
提供约束即可。约束不会关心视图中有什么,圆角与否。@benjiiiii:完全没有错误,只是按钮没有对齐…@mihatel-您的“dropbox”链接错误。。。你必须选择“共享”,然后创建一个链接。@mihatel-看看我的答案。我想你会发现这是一种更可靠的方法。关于破坏约束给出了哪些错误?如果代码破坏了约束,只需将其放在UIView
中,并给容器UIView
约束即可。约束不会关心视图中有什么,圆角与否。@benjiiiii:完全没有错误,只是按钮没有对齐…@mihatel-您的“dropbox”链接错误。。。你必须选择“共享”,然后创建一个链接。@mihatel-看看我的答案。我想你会发现这是一个更可靠的方法。它没有帮助它没有帮助同样的问题:(我正在运行它,它正在工作。你是否正确地移动了代码?是的,哪个模拟器,我正在检查iphone7,iOS11,如果你能上传zip,我会很好地运行它,并在iphone7 iOS11上比较它是否正确。查看整个文件的编辑答案。在真实设备上也是一样的,事实上,如果我滚动它解决了问题,但只有在cell rendere上同样的问题:(我在运行它,我