Number of displayed rows for fixed width UILabel and NSAttributedString

I have a UILabel whose text is dynamically set via -setAttributedText:

NSAttributedString contains many dynamic attributes, namely different fonts or styles for different character ranges here and there throughout. UILabel width is limited (via autoplay), height is variable (numberOfLines = 0).

I need to determine the number of lines of text that are rendered given the NSAttributedString constraints and width.

Please note that I am not looking for the height of the label, I am looking for the number of lines displayed. Also note that I cannot do any calculations based on font.lineHeight because the font changes across the entire NSAttributedString.

For some background I would like to set label.textAlignment=NSTextAlignmentCenter

for labels that have 1 line and label.textAlignment=NSTextAlignmentLeft

for labels that have 2 or more lines. I would do it, for example, in -[UIViewController viewDidLayoutSubviews]

after autorun, and UILabel did its business. Or perhaps there is an easier way to achieve the same goal.

+3


source to share


3 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 it helps

+1


source


This doesn't technically answer the question of how to find out the number of lines of text rendered, but I found a solution to my problem, so I thought I'd post it anyway.

What I ended up with was removing the auto-width constraint on the label (actually leading and trailing constraints for the supervisor) and adding a horizontal center to the container constraint. Then in -[UIViewController viewDidLayoutSubviews]

I installed label.preferredMaxLayoutWidth=self.view.frame.size.width-margin

. Label textAlignment=NSTextAlignmentLeft

.



This provides the same effect as the label if it is only one line and left if it is two or more.

0


source


You can install UILabel

using NSMutableAttributedString

as follows:

UILabel *contentLabel = [[UILabel alloc] initWithFrame:CGRectMake(0,0,200,100)];
[contentLabel setLineBreakMode:NSLineBreakByWordWrapping];
[contentLabel setNumberOfLines:0];
[contentLabel setFont:[UIFont systemFontOfSize:13];

NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:@"hello I am a long sentence that should break over multiple lines"];
[string addAttribute:NSFontAttributeName value:[UIFont boldSystemFontOfSize:13] range:NSMakeRange(0, [string length])];

contentLabel.attributedText = string;

      

Hope it helps ...

-2


source







All Articles