【聚沙成塔】设置 UILabel 的内边距

本文代码基于 Swift5 。

什么情况下我们需要设置 label 的内边距呢?

需要设置的情况:按字数自适应宽度的 label,并且还要有一定的边距。

如下图:标签的长度是按照字数自适应的,且左右要保持 10 pt 的间距。
pic1.png

代码解决方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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))
}
}

使用

1
2
3
4
5
6
7
8
9
10
11
12
// 创建 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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    @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 栏中的属性值即可。
Inspectors 中的属性

效果

根据字数自适应宽度,且左右边距为10pt

参考