MQoder
MQoder

Reputation: 732

How to calculate height of nsattributed string with line spacing dynamically

im trying to calculate the height of a UILabel with LineSpacing attribute. The weird thing is that calculated value of the height of the normal label.text is lower then the label.attributedText with its lineheight. it looks like i'm doing something wrong, but cant find what, so please help :D.

The provided code is specially made for SO to make it compact and clear, it is implemented differently in my project.

extension NSAttributedString {
    func heightWithWidth(width: CGFloat) -> CGFloat {
        let maxSize = CGSize(width: width, height: CGFloat.max)
        
        let boundingBox = self.boundingRectWithSize(maxSize, options: [.UsesLineFragmentOrigin, .UsesFontLeading, .UsesDeviceMetrics], context: nil)
        
        return boundingBox.height
    }
}

extension UILabel {
    
    func getHeightWithGivenWidthAndLineHeight(lineHeight: CGFloat, labelWidth: CGFloat) -> CGFloat {
        let text = self.text
        if let text = text {
            let attributeString = NSMutableAttributedString(string: text)
            let style = NSMutableParagraphStyle()
            
            style.lineSpacing = lineHeight
            attributeString.addAttribute(NSParagraphStyleAttributeName, value: style, range: NSMakeRange(0, text.characters.count))
            let height = attributeString.heightWithWidth(labelWidth)
            self.attributedText = attributeString
            return height
        }
        return 0
    }

I call this by

let contentHeight = contentLabel.text! == "" ? 0 : contentLabel.getHeightWithGivenWidthAndLineHeight(3, labelWidth: labelWidth)

Working with normal strings (without spacing) works perfectly, when i use attributedstring with lineSpacing it fails to calculate the correct value.

Upvotes: 4

Views: 5088

Answers (2)

MQoder
MQoder

Reputation: 732

I updated my Extension this way to set the line height and return the new label height at the same time. Thanx to beyowulf

extension UILabel {

    func setLineHeight(lineHeight: CGFloat, labelWidth: CGFloat) -> CGFloat {
        let text = self.text
        if let text = text {
            let attributeString = NSMutableAttributedString(string: text)
            let style = NSMutableParagraphStyle()

            style.lineSpacing = lineHeight
            attributeString.addAttribute(NSParagraphStyleAttributeName, value: style, range: NSMakeRange(0, text.characters.count))
            self.attributedText = attributeString
            return self.sizeThatFits(CGSize(width: labelWidth, height: 20)).height
        }
        return 0
    }
}

Upvotes: 0

beyowulf
beyowulf

Reputation: 15321

You can just use UILabel's sizeThatFits. For example:

    let text = "This is\nSome\nGreat\nText"

    let contentHeight = contentLabel.text! == "" ? 0 : contentLabel.getHeightWidthGivenWidthAndLineHeight(6, labelWidth: labelWidth) 
    //returns 73.2

But just setting

    contentLabel.attributedText = contentLabel.attributedString //attributedString is same as getHeightWidthGivenWidthAndLineHeight

    let size = contentLabel.sizeThatFits(contentLabel.frame.size) 
    //returns (w 49.5,h 99.5)

Code for attributedString added to your extension, if you need to see that:

var attributedString:NSAttributedString?{
        if let text = self.text{
            let attributeString = NSMutableAttributedString(string: text)
            let style = NSMutableParagraphStyle()

            style.lineSpacing = 6
            attributeString.addAttribute(NSParagraphStyleAttributeName, value: style, range: NSMakeRange(0, text.characters.count))
            return attributeString
        }
        return nil
    }

Upvotes: 4

Related Questions