多行 UILabel 导致额外的填充

Posted

技术标签:

【中文标题】多行 UILabel 导致额外的填充【英文标题】:Multi-line UILabel causing extra padding 【发布时间】:2018-09-27 20:28:41 【问题描述】:

我有一个 collectionView 单元格,它有一个标签和一个 imageView。 imageView 距离单元格顶部 8 点,标签顶部距离 imageView 底部 8 点,标签底部距离单元格底部 8 点。标签在距离单元格右边缘 -10 点时换行。

进入标签的文本可以跨越多行。我在 collectionView 的 sizeForItem 中使用以下函数来计算标签的高度:

func estimatedLabelHeight(text: String, width: CGFloat, font: UIFont) -> CGFloat 

    let size = CGSize(width: width, height: 1000)

    let options = NSStringDrawingOptions.usesFontLeading.union([.usesLineFragmentOrigin, .usesFontLeading])

    let attributes = [NSAttributedStringKey.font: font]

    let rectangleHeight = String(text).boundingRect(with: size, options: options, attributes: attributes, context: nil).height

    return rectangleHeight

单元格正确扩展,但标签添加了额外的填充,我不知道如何摆脱它。

这是一个正确换行的多行标签,大小为 22。我在 3D 检查器内拍了一张照片。如您所见,标签文本上方和下方的顶部和底部有相当多的填充。标签在 imageView 下方的 8 点间距是正确的,但额外的填充使它看起来像 24 点间距。

奇怪的是,即使我将标签的大小减小到 16,额外的填充仍然存在。

如何删除此填充?

调用estimateLabelHeight函数的collectionView的sizeForItem:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize 

    let profileImageViewHeight: CGFloat = 50 // imageView height is set to 50 inside the cell

    let padding: CGFloat = 24 // 8 x 8 x 8 the vertical padding inside the cell between the titleLabel, the imageView, and the cell

    // estimatedLabelHeight is called here
    let titleLabelHeight = estimatedLabelHeight(text: "some very very long text...", width: view.frame.width - 20, font: UIFont.systemFont(ofSize: 22))

    let totalHeightOfCell = titleLabelHeight + profileImageViewHeight + padding

    return CGSize(width: view.frame.width, height: totalHeightOfCell)

细胞:

class MyCell: UICollectionViewCell

    let titleLabel: UILabel = 
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = UIFont.systemFont(ofSize: 22)
        label.textColor = UIColor.black
        label.textAlignment = .left
        label.sizeToFit()
        label.numberOfLines = 0
        return label
    ()

    let profileImageView: UIImageView = 
        // created it...
    

    override init(frame: CGRect) 
        super.init(frame: frame)

        addSubview(profileImageView)
        addSubview(titleLabel)

        profileImageView.topAnchor.constraint(equalTo: self.topAnchor, constant: 8).isActive = true
        profileImageView.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 10).isActive = true
        profileImageView.widthAnchor.constraint(equalToConstant: 50).isActive = true
        profileImageView.heightAnchor.constraint(equalToConstant: 50).isActive = true

        titleLabel.topAnchor.constraint(equalTo: profileImageView.bottomAnchor, constant: 8).isActive = true
        titleLabel.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 10).isActive = true
        titleLabel.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -10).isActive = true
        titleLabel.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -8).isActive = true

        // I tried to set the label's height using the below but the same padding issue occured
        // let titleLabelHeight = estimatedLabelHeight(text: titleLabel.text!, width: self.frame.width - 20, font: UIFont.systemFont(ofSize: 22))
        // titleLabel.heightAnchor.constraint(greaterThanOrEqualToConstant: titleLabelHeight).isActive = true
    

【问题讨论】:

为什么在程序约束上使用“greaterThanOrEqualTo”?您是否尝试过“EqualTo”约束? 另外,我很好奇将estimatedLabelHeight 的值与布局后实际单元格视图的frame.size.height 进行比较,它们有什么不同吗? @CSmith 嘿,感谢您的建议。在尝试使用 GreaterThan 之前,我尝试使用 EqualTo 并且发生了相同的填充问题。今晚晚些时候我会向你更新这两种尺寸 @CSmith 我发现了问题。在单元格内,我将 imageView 的底部锚点设置为 8 而不是 -8,这导致与我在 sizeForItem 内填充的内容发生冲突(而不是 24,它应该是 16)。我修好了它。谢谢! @CSmith 顺便说一句,在 sizeForItem 和单元格的框架中测量高度的技巧帮助我缩小了范围。很好的建议:) 【参考方案1】:

问题是由于我自己的粗心造成的。 @CSmith 测量 sizeForItem 高度和单元格框架的提示帮助我缩小了范围。

在collectionView 单元格内的项目中,我将imageView 的底部锚点设置为8 而不是-8,在collectionView 的sizeForItem 内,我的总高度为24。因为单元格内有一个8,所以存在冲突在 collectionView 中应该是 16 并且这种不匹配以某种方式拉伸了标签。一旦我更正它并更改了 imageView 的底部锚点 -8 一切都匹配并且标签的填充问题得到解决。

【讨论】:

以上是关于多行 UILabel 导致额外的填充的主要内容,如果未能解决你的问题,请参考以下文章

UItableviewcell中的多行UIlabel使用Autolayout

如何在多行 UILabel 中找到最后一个文本行的位置,或者让 UILabel 有 0 填充

如何确保 UILabel 只占用它需要的空间,而不需要额外的填充?

iOS:UILabel 之后的 UIImageView 与多行

带有多行 UILabel 的 UIPickerView

iOS:多行 uilabel 仅显示带有自动布局的一行