开发者

How to optimally fit a NSString in a rectangle? [duplicate]

开发者 https://www.devze.com 2023-02-01 06:54 出处:网络
This question already has answers here: Closed 10 years ago. Possible Duplicate: Change NSTextField font size to fit
This question already has answers here: Closed 10 years ago.

Possible Duplicate:

Change NSTextField font size to fit

I am trying to fit a string of variable length (the number of words in the string is unknown) inside a given rectangle. I want to optimally size the string so that it is as big as possible and fits inside the rectangle. Further more, the string should word wrap if there is more than one word and that a word should not be partially rendered on multiple lines. My problem is sometimes a word is partially laid out on multiple lines as seen below. Any suggestions on what I might be doing wrong?

Thank you.

How to optimally fit a NSString in a rectangle? [duplicate]

I am using an NSLayoutManager, NSTextStorage and NSTextContainer.

I initialize everything as follow开发者_运维问答s:

    textStorage = [[NSTextStorage alloc] initWithString:@""];
    layoutManager = [[NSLayoutManager alloc] init];
    textContainer = [[NSTextContainer alloc] init];

    [layoutManager addTextContainer:textContainer];     
    [textStorage addLayoutManager:layoutManager];   

    paraStyle = [[NSMutableParagraphStyle alloc] init];
    [paraStyle setLineBreakMode:NSLineBreakByWordWrapping];
    [paraStyle setParagraphStyle:[NSParagraphStyle defaultParagraphStyle]];
    [paraStyle setAlignment:NSCenterTextAlignment];

I then compute the font size as follows,

- (float)calculateFontSizeForString:(NSString *)aString andBoxSize:(NSSize)aBox
{
    //Create the attributed string
    NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:aString];
    [textStorage setAttributedString:attrString];
    [textContainer setContainerSize:NSMakeSize(aBox.width, FLT_MAX)];   
    [attrString release]; //Clean up

    //Initial values
    float fontSize = 50.0;
    float fontStepSize = 100.0;
    NSRect stringRect;
    BOOL didFindHeight = NO;
    BOOL shouldIncreaseHeight = YES;

    while (!didFindHeight)
    {   
        NSMutableDictionary *stringAttributes = [NSMutableDictionary dictionaryWithObjectsAndKeys:
                                                 paraStyle, NSParagraphStyleAttributeName,
                                                 [NSFont systemFontOfSize:fontSize], NSFontAttributeName, nil];

        [textStorage addAttributes:stringAttributes range:NSMakeRange(0, [textStorage length])];

        (void)[layoutManager glyphRangeForTextContainer:textContainer];     
        stringRect = [layoutManager usedRectForTextContainer:textContainer];

        if (shouldIncreaseHeight)
        {
            if (stringRect.size.height > aBox.height)
            {
                shouldIncreaseHeight = NO;
                fontStepSize = fontStepSize/2;
            }

            fontSize += fontStepSize;
        }
        else
        {
            if (stringRect.size.height < aBox.height)
            {
                shouldIncreaseHeight = YES;

                fontStepSize = fontStepSize/2;

                if (fontStepSize <= 0.5)
                {
                    didFindHeight = YES;
                }
            }

            if ((fontSize - fontStepSize) <= 0)
            {
                fontStepSize = fontStepSize/2;              
            }
            else
            {
                fontSize -= fontStepSize;
            }
        }
    }

    return fontSize;
}


Please search before posting. This comes up repeatedly. Latest answer is here, but I think there're more complete answers with code listings elsewhere.

My admittedly simple example shows how to do it without a text container and layout manager but your approach is more robust. Unfortunately brute-force (sizing down until it fits) is the only approach for determining the best fit.

0

精彩评论

暂无评论...
验证码 换一张
取 消