本文代码基于 Swift5 。
什么情况下我们需要设置 label 的内边距呢?
需要设置的情况:按字数自适应宽度的 label,并且还要有一定的边距。
如下图:标签的长度是按照字数自适应的,且左右要保持 10 pt 的间距。
该需求也可通过在 view 上添加一个 label 实现。
设置 UILabel 的内边距
class InsetLabel: UILabel {
// 1.定义一个接受间距的属性
var textInsets = UIEdgeInsets.zero
//2. 返回 label 重新计算过 text 的 rectangle
override func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect {
guard text != nil else {
return super.textRect(forBounds: bounds, limitedToNumberOfLines: numberOfLines)
}
let insetRect = bounds.inset(by: textInsets)
let textRect = super.textRect(forBounds: insetRect, limitedToNumberOfLines: numberOfLines)
let invertedInsets = UIEdgeInsets(top: -textInsets.top,
left: -textInsets.left,
bottom: -textInsets.bottom,
right: -textInsets.right)
return textRect.inset(by: invertedInsets)
}
//3. 绘制文本时,对当前 rectangle 添加间距
override func drawText(in rect: CGRect) {
super.drawText(in: rect.inset(by: textInsets))
}
}
使用
// 创建 label 并赋值
let firstLabel = InsetLabel()
firstLabel.text = "哈哈哈哈"
firstLabel.textInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10)
view.addSubview(firstLabel)
// 设置 label 的相关约束
firstLabel.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
firstLabel.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 100),
firstLabel.rightAnchor.constraint(lessThanOrEqualTo: view.rightAnchor, constant: -100),
firstLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 200)
])
代码解读
首先创建一个 UILabel 的子类 InsetLabel ,在类里面定义一个接受间距的属性: textInsets。然后通过重写 textRect(forBounds:limitedToNumberOfLines:) 方法来返回添加了间距的正确 bounds。
最后,通过重写 drawTextInRect: 方法,用正确的 bounds 来绘制文本内容。
textRect(forBounds:limitedToNumberOfLines:):在系统执行其他文本布局计算之前,在子类重写该方法来实现需要的 label bounds。drawTextInRect::重写该方法来配置当前的上下文,然后调用父类的方法来进行真正的绘制。
支持IB
@IBDesignable
extension InsetLabel {
@IBInspectable
var leftTextInset: CGFloat {
set { textInsets.left = newValue }
get { return textInsets.left}
}
@IBInspectable
var rightTextInset: CGFloat {
set { textInsets.right = newValue }
get { return textInsets.right}
}
@IBInspectable
var topTextInset: CGFloat {
set { textInsets.top = newValue }
get { return textInsets.top}
}
@IBInspectable
var bottomTextInset: CGFloat {
set { textInsets.bottom = newValue }
get { return textInsets.bottom}
}
}
使用
直接设置 IB 中 Inspectors 栏中的属性值即可。