如何调整UILabel的垂直居中?

发布于 2025-01-09 19:53:02 字数 2641 浏览 4 评论 0原文

我在 UILabel 中创建了设置行高和字母间距的函数。

extension UILabel {
    func apply(lineHeight: CGFloat, letterSpacing: CGFloat = 0) {
        let attributedString = NSMutableAttributedString(string: text ?? " ")
        let range = NSMakeRange(0, attributedString.length)
        
        // Line Height
        let style = NSMutableParagraphStyle()
        style.minimumLineHeight = lineHeight
        style.maximumLineHeight = lineHeight
        attributedString.addAttribute(.paragraphStyle, value: style, range: range)
        attributedString.addAttribute(.baselineOffset, value: (lineHeight - font.lineHeight) / 2, range: range)
        
        // Letter Spacing
        attributedString.addAttribute(.kern, value: letterSpacing, range: range)
        
        attributedText = attributedString
    }
}

我应用了我的标签。

但发生了一些非常奇怪的事情。

下面的所有代码都是相同的。

唯一的区别在于更改标签文本的时间。

我不明白为什么会发生这种情况。

有什么问题吗?

override func viewDidLoad() {
        super.viewDidLoad()
        
        
        let label1 = UILabel()
        label1.font = .systemFont(ofSize: 32, weight: .bold)
        label1.apply(lineHeight: 48)
        label1.text = "This is test1"
        label1.translatesAutoresizingMaskIntoConstraints = false
        
        let label2 = UILabel()
        label2.text = "This is test2"
        label2.font = .systemFont(ofSize: 32, weight: .bold)
        label2.apply(lineHeight: 48)
        label2.translatesAutoresizingMaskIntoConstraints = false
        
        let label3 = UILabel()
        label3.text = "This is test3"
        label3.font = .systemFont(ofSize: 32, weight: .bold)
        label3.apply(lineHeight: 48)
        label3.translatesAutoresizingMaskIntoConstraints = false
        
        view.addSubview(label1)
        view.addSubview(label2)
        view.addSubview(label3)
        
        NSLayoutConstraint.activate([
            label1.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            label1.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            
            label2.topAnchor.constraint(equalTo: label1.bottomAnchor, constant: 8),
            label2.centerXAnchor.constraint(equalTo: label1.centerXAnchor),
            
            label3.topAnchor.constraint(equalTo: label2.bottomAnchor, constant: 8),
            label3.centerXAnchor.constraint(equalTo: label1.centerXAnchor)
        ])
    }

输入图片此处描述

I made function that set line height and letter spacing in UILabel.

extension UILabel {
    func apply(lineHeight: CGFloat, letterSpacing: CGFloat = 0) {
        let attributedString = NSMutableAttributedString(string: text ?? " ")
        let range = NSMakeRange(0, attributedString.length)
        
        // Line Height
        let style = NSMutableParagraphStyle()
        style.minimumLineHeight = lineHeight
        style.maximumLineHeight = lineHeight
        attributedString.addAttribute(.paragraphStyle, value: style, range: range)
        attributedString.addAttribute(.baselineOffset, value: (lineHeight - font.lineHeight) / 2, range: range)
        
        // Letter Spacing
        attributedString.addAttribute(.kern, value: letterSpacing, range: range)
        
        attributedText = attributedString
    }
}

And I apply that my label.

But something very strange happens.

All of the codes below are the same.

The only difference is when you change the label's text.

I can't understand why this is happening.

What's the problem?

override func viewDidLoad() {
        super.viewDidLoad()
        
        
        let label1 = UILabel()
        label1.font = .systemFont(ofSize: 32, weight: .bold)
        label1.apply(lineHeight: 48)
        label1.text = "This is test1"
        label1.translatesAutoresizingMaskIntoConstraints = false
        
        let label2 = UILabel()
        label2.text = "This is test2"
        label2.font = .systemFont(ofSize: 32, weight: .bold)
        label2.apply(lineHeight: 48)
        label2.translatesAutoresizingMaskIntoConstraints = false
        
        let label3 = UILabel()
        label3.text = "This is test3"
        label3.font = .systemFont(ofSize: 32, weight: .bold)
        label3.apply(lineHeight: 48)
        label3.translatesAutoresizingMaskIntoConstraints = false
        
        view.addSubview(label1)
        view.addSubview(label2)
        view.addSubview(label3)
        
        NSLayoutConstraint.activate([
            label1.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            label1.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            
            label2.topAnchor.constraint(equalTo: label1.bottomAnchor, constant: 8),
            label2.centerXAnchor.constraint(equalTo: label1.centerXAnchor),
            
            label3.topAnchor.constraint(equalTo: label2.bottomAnchor, constant: 8),
            label3.centerXAnchor.constraint(equalTo: label1.centerXAnchor)
        ])
    }

enter image description here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

人生百味 2025-01-16 19:53:02

这可能被认为是一个“错误”——值得报告。

如果您在设置属性文本之后设置 .text 属性,则不会应用段落样式中的行高。

您可以通过添加以下内容来确认这一点:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let v = view.subviews[1] as? UILabel {
        v.text = "This is test2"
    }
}

当您点击视图时,您的第二个标签将“丢失”其行高设置。

奇怪的是,解决这个问题的方法是在设置标签的 .text 属性后引用标签的 .attributedText 属性

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let v = view.subviews[1] as? UILabel {
        v.text = "This is test2"
        _ = v.attributedText
    }
}

:显然,会导致 UIKit “更新”段落行高样式。

因此,对于您的具体示例,在 viewDidLoad() 末尾添加此内容

[label1, label2, label3].forEach { v in
    _ = v.attributedText
}

将导致所有 3 个标签具有相同的外观。

This could possibly be considered a "bug" - worth reporting.

If you set the .text property after setting the attributed text, the line height in the paragraph style does not get applied.

You can confirm this by adding this:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let v = view.subviews[1] as? UILabel {
        v.text = "This is test2"
    }
}

When you tap the view, your 2nd label will "lose" it's line height setting.

Curiously, the way around this is to reference the label's .attributedText property after setting its .text property:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let v = view.subviews[1] as? UILabel {
        v.text = "This is test2"
        _ = v.attributedText
    }
}

which, apparently, will cause UIKit to "update" the paragraph line height style.

So, for your specific example, adding this at the end of viewDidLoad():

[label1, label2, label3].forEach { v in
    _ = v.attributedText
}

will result in all 3 labels having the same appearance.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文