Kegham K.
Kegham K.

Reputation: 1614

How to center UILabel text top and bottom spaces

I have a UILabel in a stackview in a content view that is in a tableview cell. Everything is working correctly and the cell is resizing but i cannot center the text in the UILabel. I always have strange spaces in the bottom of the text. Check out screen shot.

Yellow: content view Green: stackview Blue: label

Additional info: No static height for cells. The yellow view has top bottom and trailing and leading constraints plus horizontal and vertical aligned to super view same thing the stack view. The only thing that has constant height which I activate and deactivate through code is the button. So it hides and shows according to the cell. Stackview is fill proportionally.

The UILabel is sizeToFit

Also tried:

detailLbl.textAlignment = .center
detailLbl.lineBreakMode = .byWordWrapping //also tried byClipping
detailLbl.baselineAdjustment = .alignCenters

The text inside i parse as HTML

"<p><font color=\"#cd1719\">V/. </font>…The Word of the Lord.<br><b></b><font color=\"#cd1719\">R/. </font><b>Thanks be to God.</b></p>"

Second screenshot

"<h6 lang=\"en\" style=\"color=#cd1719 !important; font-weight: normal !important\"><font color=\"#cd1719\" weight=\"normal\"><i>The alleluia is said or sung.</i></font></h6>"

This is an NSAttributedString extension I use for parsing HTML

 extension NSAttributedString {

    convenience init(htmlString html: String, font: UIFont? = nil, useDocumentFontSize: Bool = true) throws {
        let options: [NSAttributedString.DocumentReadingOptionKey : Any] = [
            .documentType: NSAttributedString.DocumentType.html,
            .characterEncoding: String.Encoding.utf8.rawValue
        ]

        let data = html.data(using: .utf8, allowLossyConversion: true)
        guard (data != nil), let fontFamily = font?.familyName, let attr = try? NSMutableAttributedString(data: data!, options: options, documentAttributes: nil) else {
            try self.init(data: data ?? Data(html.utf8), options: options, documentAttributes: nil)
            return
        }

        let fontSize: CGFloat? = useDocumentFontSize ? nil : font!.pointSize
        let range = NSRange(location: 0, length: attr.length)
        attr.enumerateAttribute(.font, in: range, options: .longestEffectiveRangeNotRequired) { attrib, range, _ in
            if let htmlFont = attrib as? UIFont {
                let traits = htmlFont.fontDescriptor.symbolicTraits
                var descrip = htmlFont.fontDescriptor.withFamily(fontFamily)

                if (traits.rawValue & UIFontDescriptor.SymbolicTraits.traitBold.rawValue) != 0 {
                    descrip = descrip.withSymbolicTraits(.traitBold)!
                }

                if (traits.rawValue & UIFontDescriptor.SymbolicTraits.traitItalic.rawValue) != 0 {
                    descrip = descrip.withSymbolicTraits(.traitItalic)!
                }
                
                attr.addAttribute(.font, value: UIFont(descriptor: descrip, size: fontSize ?? htmlFont.pointSize), range: range)
            }
        }

        self.init(attributedString: attr)
    }

}

And this is how I use it in the code

if let attributedString = try? NSAttributedString(htmlString: htmlTxt, font: UIFont(name: "Avenir-Roman", size: CGFloat(Constants.defualtContentDescriptionFontSize)), useDocumentFontSize: false) {
        cell.detailLbl.attributedText = attributedString
}

enter image description here enter image description here

Upvotes: 0

Views: 391

Answers (1)

DonMag
DonMag

Reputation: 77647

Part of the problem is that you are using formatted html text, which includes the "extra space."

For example, your first html text line includes <p> </p> tags.

This code creates two green-background labels, each the same width, each with no height constraint:

class ViewController: UIViewController, UIScrollViewDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        let firstLabel = UILabel()
        firstLabel.backgroundColor = .green
        firstLabel.numberOfLines = 0
        firstLabel.translatesAutoresizingMaskIntoConstraints = false

        let secondLabel = UILabel()
        secondLabel.backgroundColor = .green
        secondLabel.numberOfLines = 0
        secondLabel.translatesAutoresizingMaskIntoConstraints = false
        
        view.addSubview(firstLabel)
        view.addSubview(secondLabel)

        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            
            // first label 40-pts from top, 20-pts on each side
            firstLabel.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
            firstLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            firstLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),

            // second label 40-pts from bottom of first label, 20-pts on each side
            secondLabel.topAnchor.constraint(equalTo: firstLabel.bottomAnchor, constant: 40.0),
            secondLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            secondLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
            
        ])
        
        var htmlTxt = "<p><font color=\"#cd1719\">V/. </font>…The Word of the Lord.<br><b></b><font color=\"#cd1719\">R/. </font><b>Thanks be to God.</b></p>"
        
        if let attributedString = try? NSAttributedString(htmlString: htmlTxt, font: UIFont(name: "Avenir-Roman", size: 24.0), useDocumentFontSize: false) {
            firstLabel.attributedText = attributedString
            //cell.detailLbl.attributedText = attributedString
        }

        htmlTxt = "<font color=\"#cd1719\">V/. </font>…The Word of the Lord.<br><b></b><font color=\"#cd1719\">R/. </font><b>Thanks be to God.</b>"
        
        if let attributedString = try? NSAttributedString(htmlString: htmlTxt, font: UIFont(name: "Avenir-Roman", size: 24.0), useDocumentFontSize: false) {
            secondLabel.attributedText = attributedString
            //cell.detailLbl.attributedText = attributedString
        }
    }

}

The output:

enter image description here

The difference between the two? For the second label, I removed the <p> </p> tags before processing the html with your extension.

Your second html text defines it as h6 ... here's the output with that string:

enter image description here

Again, the difference between the two is that I removed the h6 tag before processing the html.

You'll probably need to modify your extension to remove the paragraph tags, or set a paragraph style that would ignore them.

Upvotes: 1

Related Questions