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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With