Search code examples
iosswiftuilabeluicollectionviewcellcgsize

Multi-line UILabel causing extra padding


I have a collectionView cell that has a label and an imageView. The imageView is 8 points from the top of the cell, the top of the label is 8 points from the bottom of the imageView, and the bottom of the label is 8 points from the bottom of the cell. The label wraps when it gets -10 point away from the right edge of the cell.

The text that goes into the label can span several lines. I use the below function inside the collectionView's sizeForItem to calculate the label's height:

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
}

The cell expands correctly but the label has extra padding that is added to it and I cannot figure out how to get rid of it.

enter image description here

That is a multi line label size 22 that correctly wraps. I took a picture of it inside the 3D inspector. As you can see there is quite an extra bit of padding on the top and bottom above and below the label text. The label's 8 point spacing below the imageView is correct but the extra padding makes it look like 24 points of spacing.

The odd thing is even when I reduced the label's size to 16 the extra padding was still there.

How can I remove this padding?

The collectionView's sizeForItem where the estimatedLabelHeight function is called:

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)
}

The cell:

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
    }
}

Solution

  • The problem was due to my own carelessness. @CSmith tip of measuring up the height in sizeForItem and the cell's frame is what helped me narrow it down.

    Inside the project inside the collectionView cell I had the the imageView's bottom anchor set to 8 instead of -8 and inside the collectionView's sizeForItem I had the total height of 24. There was a conflict because since I had a 8 inside the cell it should've been 16 inside the collectionView and that mismatch was somehow stretching out the label. Once I corrected it and changed the imageView's bottom anchor -8 everything matched up and the label's padding issue was resolved.