我在Interface Builder中制作了一个标签,其中包含固定高度和固定宽度的约束:
我将它子类化为白色圆形边框:
class CircularLabel: UILabel {
override func awakeFromNib() {
super.awakeFromNib()
layer.cornerRadius = frame.size.height / 2
layer.borderColor = UIColor.white.cgColor
layer.borderWidth = 5
layer.masksToBounds = true
clipsToBounds = true
}
}
我期待一个完美的白色边框,没有橙色像素。
iPhone 8(模拟器和真实设备),iOS 11.2,Xcode 9.2,Swift 3.2
答案 0 :(得分:1)
您应该使用UIBezierPath来圆角并使用相同的路径绘制边框线。 我的情况是我创建了CAShapeLayer并进行了所有调整,并将其添加为查看子图层。
let borderLayer = CAShapeLayer()
let shapeLayer = CAShapeLayer()
let path = UIBezierPath(roundedRect: *get your view bounds*, cornerRadius: *needed radius*).cgPath
//Set this rounding path to both layers
shapeLayer.path = path
borderLayer.path = path
//adjust border layer
borderLayer.lineWidth = *border width*
borderLayer.strokeColor = *cgColor of your border*
//apply shape layer as mask to your view, it will cut your view by the corners
*yourViewInstance*.layer.mask = shapeLayer
//Set fill color for border layer as clear, because technically it just puts colored layer over your view
borderLayer.fillColor = UIColor.clear.cgColor
//Add border layer as sublayer to your view's main layer
*your view instance*.layer.addSublayer(borderLayer)
在您的情况下,动态标签的文字可能存在问题:如果文字是例如将在边界下绘制900000。要解决这个问题,您可以将UILAbel放在另一个视图中(包含形状和边框调整)并对其进行布局
例如:
Structure and constraints
What i got: container BG - orange, border - white, superview's BG - red
Controller的viewDidLoad方法代码:
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.red
self.containerView.backgroundColor = UIColor.orange
self.label.backgroundColor = UIColor.clear
self.label.textAlignment = .center
self.label.adjustsFontSizeToFitWidth = true
self.label.text = "9000000"
//Create Border and shape and apply it to container view
let borderLayer = CAShapeLayer()
let shapeLayer = CAShapeLayer()
let path = UIBezierPath(roundedRect: containerView.bounds, cornerRadius: containerView.bounds.width / 2).cgPath
//Set this rounding path to both layers
shapeLayer.path = path
borderLayer.path = path
//adjust border layer
borderLayer.lineWidth = 20
borderLayer.strokeColor = UIColor.white.cgColor
//apply shape layer as mask to your view, it will cut your view by the corners
self.containerView.layer.mask = shapeLayer
//Set fill color for border layer as clear, because technically it just puts colored layer over your view
borderLayer.fillColor = UIColor.clear.cgColor
//Add border layer as sublayer to your view's main layer
self.containerView.layer.addSublayer(borderLayer)
}
答案 1 :(得分:0)
另一个解决方案是完全忘记不完美的borderWidth
并在彼此内部使用两个视图:
extension UIView {
func roundBounds() {
layer.cornerRadius = frame.size.height / 2
clipsToBounds = true
}
}
class RoundLabel: UILabel {
override func awakeFromNib() {
super.awakeFromNib()
roundBounds()
}
}
class RoundView: UIView {
override func awakeFromNib() {
super.awakeFromNib()
roundBounds()
}
}
答案 2 :(得分:0)
神秘解决了。
添加1个像素的笔划,masksToBounds
将完成剪裁边缘的工作:
override func draw(_ rect: CGRect) {
super.draw(rect)
// workaround incomplete borders: https://stackoverflow.com/a/48663935/1033581
UIColor(cgColor: layer.borderColor!).setStroke()
let path = UIBezierPath(roundedRect: bounds, cornerRadius: layer.cornerRadius)
path.lineWidth = 1
path.stroke()
}
实际上,根据我的测试,设置layer.borderWidth = 5
等同于公式:
let borderWidth: CGFloat = 5
UIColor(cgColor: layer.borderColor!).setStroke()
let path = UIBezierPath(roundedRect: bounds.insetBy(dx: borderWidth / 2, dy: borderWidth / 2),
cornerRadius: layer.cornerRadius - borderWidth / 2)
path.lineWidth = borderWidth
path.stroke()
但另一方面,layer.cornerRadius = frame.size.height / 2
+ layer.masksToBounds = true
将使用不同的未知方法进行剪辑,该方法在边缘上具有不同的锯齿公式。由于剪裁和绘图没有相同的锯齿,因此有些像素显示背景颜色而不是边框颜色。