UILabel 子类 - 尽管标签高度正确,但文本在底部被截断

Posted

技术标签:

【中文标题】UILabel 子类 - 尽管标签高度正确,但文本在底部被截断【英文标题】:UILabel subclass - text cut off in bottom despite label being correct height 【发布时间】:2016-07-10 15:17:03 【问题描述】:

UILabel 子类在底部截断文本时遇到问题。标签的高度适合文本,底部还有一些空间,但文本仍然被截断。

红色条纹是添加到标签层的边框。

我对标签进行子类化以添加边缘插图。

override func sizeThatFits(size: CGSize) -> CGSize 
    var size = super.sizeThatFits(size)
    size.width += insets.left + insets.right
    size.height += insets.top + insets.bottom
    return size


override func drawTextInRect(rect: CGRect) 
    super.drawTextInRect(UIEdgeInsetsInsetRect(rect, insets))

但是,在这种特殊情况下,插图为零。

【问题讨论】:

由于标签的高度小于字体大小或减小字体大小,尝试增加UILabel高度。 如您所见,文字高度低于标签高度。另外,如果我使用常规标签而不是这个子类,文本不会被截断。 @mag_zbc 您使用的是哪种自定义字体。 对我有用的是允许包含视图变得更高,如Height >= 【参考方案1】:

原来问题出在

self.lineBreakMode = .ByClipping

改成

self.lineBreakMode = .ByCharWrapping

解决了问题

【讨论】:

【参考方案2】:

同时为标签提供 topAnchor 和 centerYAnchor 时发生在我身上。 只留下一个锚就解决了这个问题。

【讨论】:

【参考方案3】:

其他答案对我没有帮助,但所做的是将标签的高度限制为所需的任何高度,如下所示:

let unconstrainedSize = CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude)
label.heightAnchor.constraint(equalToConstant: label.sizeThatFits(unconstrainedSize).height).isActive = true

此外,如果标签的 text 字段为 nil 或等于 ""sizeThatFits(_:) 将返回 0 by 0 大小

【讨论】:

【参考方案4】:

我的问题是标签的(垂直)内容抗压缩优先级不够高;将其设置为所需的 (1000) 即可修复它。

看起来其他非 OP 答案可能是解决同一潜在问题的某种解决方法。

【讨论】:

【参考方案5】:

我也遇到过这个问题,但想避免添加高度限制。我已经创建了一个UILabel 子类,它允许我添加内容插入(但为了将tableHeaderView 直接设置为标签,而不必将其包含在另一个视图中)。使用该类,我可以设置底部插图来解决字体裁剪问题。

import UIKit

@IBDesignable class InsetLabel: UILabel 

    @IBInspectable var topInset: CGFloat = 16
    @IBInspectable var bottomInset: CGFloat = 16
    @IBInspectable var leftInset: CGFloat = 16
    @IBInspectable var rightInset: CGFloat = 16
    var insets: UIEdgeInsets 
        get 
            return UIEdgeInsets(
                top: topInset,
                left: leftInset,
                bottom: bottomInset,
                right: rightInset
            )
        
    

    override func drawText(in rect: CGRect) 
        super.drawText(in: rect.inset(by: insets))
    

    override var intrinsicContentSize: CGSize 
        return addInsetsTo(size: super.intrinsicContentSize)
    

    override func sizeThatFits(_ size: CGSize) -> CGSize 
        return addInsetsTo(size: super.sizeThatFits(size))
    

    func addInsetsTo(size: CGSize) -> CGSize 
        return CGSize(
            width: size.width + leftInset + rightInset,
            height: size.height + topInset + bottomInset
        )
    


这可以简化为仅将字体剪裁为:

import UIKit

class FontFittingLabel: UILabel 

    var inset: CGFloat = 16 // Adjust this

    override func drawText(in rect: CGRect) 
        super.drawText(in: rect.inset(by: UIEdgeInsets(
            top: 0,
            left: 0,
            bottom: inset,
            right: 0
        )))
    

    override var intrinsicContentSize: CGSize 
        let size = super.intrinsicContentSize
        return CGSize(
            width: size.width,
            height: size.height + inset
        )
    


【讨论】:

我怀疑某些字体存在配置问题,导致此错误。非常好的解决方案。 这不适用于很长的文本。最后两个字总是被删掉。 UILabel 似乎无论任何人尝试什么都会被切断,这令人抓狂。解决方案是直接切换到 textView ——希望我很久以前就这样做了,因为 UILabel 是一个完整而彻底的 Apple 噩梦,包裹在龙卷风中。【参考方案6】:

Helvetica Neue Condensed Bold 字体我也遇到了同样的问题。将标签的 Baseline 属性从 Align Baselines 更改为 Align Centers 对我有用.您可以通过选择标签在情节提要中轻松更改此设置。

【讨论】:

这里也一样。使用 Helvetica Neue Condensed Bold 作为文本标签。设置属性有帮助。 如果不起作用,请尝试“.none”。我提交了一个答案,解释了这种略有不同的方法以及为什么“.alignCenters”解决方案只能在某些时候起作用。【参考方案7】:

TL'DR

您要查找的属性可能是UILabelbaselineAdjustment

需要它是因为旧的 UILabel 的已知错误。试试看:

label.baselineAdjustment = .none

也可以通过界面生成器进行更改。此属性可以在 UILabel 的属性检查器 下找到,名称为 "Baseline"


说明

这是一个错误

有一些讨论,如this one,关于 UILabel 的文本边界框上的一个错误。在我们的案例中我们观察到的是这个错误的某个版本。当我们通过 AutoShrink .minimumFontScale.minimumFontSize 收缩文本时,边界框的高度似乎会增加

因此,边界框变得比行高和 UILabel 高度的可见部分更大。也就是说,将baselineAdjustment 属性设置为默认状态.alignBaselines,文本与裁剪后的底部对齐,我们可以观察到线剪裁。

理解这种行为对于解释为什么 set .alignCenters 解决一些问题而不解决其他问题至关重要。只是在较大的边界框上居中文本仍然可以剪辑它。


解决方案

所以最好的办法是设置

label.baselineAdjustment = .none

.none 案例的文档说:

相对于边界框的左上角调整文本。这 是默认调整。

由于绑定框原点与标签的框架匹配,它应该可以解决启用AutoShrink 的单行标签的任何问题。

也可以通过界面生成器进行更改。此属性可以在 UILabel 的属性检查器 下找到,名称为 "Baseline"


文档

你可以在这里阅读更多关于 UILabel 的 baselineAdjustment官方documentation。

【讨论】:

您的解释有道理,但不适用于我的情况。我不知道为什么。【参考方案8】:

我有一个垂直的UIStackView,底部有一个UILabel。这个UILabel 正在切断低于基线的字母(qgy 等),但仅当嵌套在水平的UIStackView 中时。解决方法是将.lastBaseline 对齐修饰符添加到外部堆栈视图。

    lazy var stackView: UIStackView = 
        let stackView = UIStackView(arrangedSubviews: [
            aVerticalStackWithUILabelAtBottom, // <-- bottom UILabel was cutoff
            UIView(),
            someOtherView 
        ])
        stackView.axis = .horizontal
        stackView.spacing = Spacing.one
        stackView.alignment = .lastBaseline // <-- BOOM fixed it
        stackView.isUserInteractionEnabled = true
        return stackView
    ()

【讨论】:

以上是关于UILabel 子类 - 尽管标签高度正确,但文本在底部被截断的主要内容,如果未能解决你的问题,请参考以下文章

如何滚动 UIlabel 文本并在目标 c 中动态设置它的宽度和高度

如何根据标签可用的高度调整 UILabel 字体大小

UILabel 在添加文本时反弹

获取动态UILabel的高度

尽管尺寸正确,但标签栏图标太小

UILabel 高度如何以编程方式在 Swift 中根据文本高度