Change NSTextField's height according to Font/Size

3.5k views Asked by At

Ok, here's my situation :

  • I've got an NSTextField, set up as Multi-line Text Label
  • The NSTextField is supposed to be holding just ONE line of text (even if it's a multi-line one)
  • The NSTextField has a fixed height.
  • The Font and Font Size are changed by the user

The issue :

  • Depending on the font used, and size, the bottom part of the text goes missing (as it goes beyond the NSTextField's boundaries

What I want :

  • Get the Text height, based on selection (Font & Font Size) and set the NSTextField's height accordingly.

I know it may sound complicated, but I also know it CAN be done.

Any ideas? Any reference to point me to?

3

There are 3 answers

5
Sharanya K M On BEST ANSWER

You can take the size of the string and then change the height accordingly

NSString *text = // your string
CGSize constraint = CGSizeMake(210, 20000.0f);
CGSize size = [text sizeWithFont:[UIFont fontWithName:@"Helvetica-Light" size:14] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];

UITextField *cellTextLabel = [[UITextField alloc] initWithFrame:CGRectMake(70, 9, 230, size.height)];
cellTextLabel.lineBreakMode = UILineBreakModeWordWrap;
cellTextLabel.numberOfLines = 50;
cellTextLabel.backgroundColor = [UIColor clearColor];
cellTextLabel.text = text;
cellTextLabel.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:14];
[self.view addSubview:cellTextLabel];
[cellTextLabel release];
0
marcusthierfelder On

As @valvoline said, this is working, however you get a lot of CGContext warnings like CGContextGetFontRenderingStyle: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable. if you do this outside of drawRect. Best solution is to not use drawGlyphsForGlyphRange: as the apple Documentation https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/TextLayout/Tasks/StringHeight.html#//apple_ref/doc/uid/20001809-CJBGBIBB tells.

0
valvoline On

As already said, NSTextField and UITextField are very different objects (contrary to what their name suggests). Specifically, for NSTextField you could use an elegant solution involving the NSLayoutManager. An NSLayoutManager object coordinates the layout and display of characters held in an NSTextStorage object. It maps Unicode character codes to glyphs, sets the glyphs in a series of NSTextContainer objects, and displays them in a series of NSTextView objects.

All that you need is to create a NSLayoutManager an NSTextContainer and an NSTextStorage. They wrap all together in a similar fashion:

.-----------------------.
|     NSTextStorage     | 
|  .-----------------.  |
|  | NSLayoutManager |  |
|  '-----------------'  |
|  | NSTextStorage   |  |
|  '-----------------'  |
|                       |
'-----------------------'

That said, you can use the layoutManager method usedRectForTextContainer: to estimate the correct size containing your desired text.

The following should work for your problem:

- (float)heightForStringDrawing:(NSString *)aString withFont:(NSFont *)aFont andWitdh:(float)myWidth
{
    NSTextStorage *textStorage = [[NSTextStorage alloc] initWithString:aString];
    NSTextContainer *textContainer = [[NSTextContainer alloc] initWithContainerSize:NSMakeSize(myWidth,CGFLOAT_MAX)];

    NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
    [layoutManager setTypesetterBehavior:NSTypesetterBehavior_10_2_WithCompatibility];
    [layoutManager addTextContainer:textContainer];
    [textStorage addLayoutManager:layoutManager];

    [textStorage addAttribute:NSFontAttributeName value:aFont
                        range:NSMakeRange(0,[textStorage length])];
    [textContainer setLineFragmentPadding:0.0];

    NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer];
    [layoutManager drawGlyphsForGlyphRange: glyphRange atPoint:NSMakePoint(0, 0)];

    return [layoutManager usedRectForTextContainer:textContainer].size.height;
}

There's an exhaustive Apple document about this topic:

https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/TextLayout/Tasks/StringHeight.html#//apple_ref/doc/uid/20001809-CJBGBIBB

Also, some veterans have dissected the problem on Apple Mailing List some times ago:

http://lists.apple.com/archives/cocoa-dev/2006/Jan/msg01874.html