Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Number of rendered lines for UILabel with fixed width and NSAttributedString

I have a UILabel whose text is set dynamically via -setAttributedText: The NSAttributedString contains a variety of dynamic attributes, namely different fonts or styles for different ranges of characters here and there throughout. The width of the UILabel is constrained (via autolayout), the height is variable (numberOfLines=0).

What I need to determine is the number of lines of text which are rendered given the NSAttributedString and width constraint.

Please note that I am not looking for the height of the label, I am looking for the number of rendered lines. Also note that I can't perform any computations based on font.lineHeight because the font varies throughout the NSAttributedString.

For some background, what would like to do is set label.textAlignment=NSTextAlignmentCenter for labels which have 1 line and label.textAlignment=NSTextAlignmentLeft for labels which have 2 or more lines. I would do this for example in -[UIViewController viewDidLayoutSubviews] after autolayout and the UILabel have done their business. Or perhaps there is an easier way to achieve the same goal.

like image 469
hyperspasm Avatar asked Mar 18 '23 12:03

hyperspasm


1 Answers

Here is Swift 3 version

extension NSAttributedString {

    func numberOfLines(with width: CGFloat) -> Int {

        let path = UIBezierPath(rect: CGRect(x: 0, y: 0, width: width, height: CGFloat(MAXFLOAT)))
        let frameSetterRef : CTFramesetter = CTFramesetterCreateWithAttributedString(self as CFAttributedString)
        let frameRef: CTFrame = CTFramesetterCreateFrame(frameSetterRef, CFRangeMake(0, 0), path.cgPath, nil)

        let linesNS: NSArray  = CTFrameGetLines(frameRef)

        guard let lines = linesNS as? [CTLine] else { return 0 }
        return lines.count
    }
}

Hope this helps

like image 78
saa Avatar answered Apr 06 '23 12:04

saa