iOS - How to find the right font size (in points)

2019-04-08 02:49发布

问题:

Heading pretty much explains it. I have an image that I'm drawing text on. I want the text to be sized according to the size of the image and want to find a way to get a height for the font that is just a little shorter than the image itself.

回答1:

OK, so for everyone who thinks an iteration is not avoidable:

NSString *string = @"The string to render";
CGRect rect = imageView.frame;

UIFont *font = [UIFont fontWithSize:12.0]; // find the height of a 12.0pt font
CGSize size = [string sizeWithFont:font];
float pointsPerPixel = 12.0 / size.height; // compute the ratio
// Alternatively:
// float pixelsPerPoint = size.height / 12.0;
float desiredFontSize = rect.size.height * pointsPerPixel;
// Alternatively:
// float desiredFontSize = rect.size.height / pixelsPerPoint;

desiredFontSize will contain the font size in points of which the height is exactly the same as the height of the specified rectangle. You may want to multiply it by, say, 0.8 to make the font a bit smaller than the rect's actual size to make it look good.



回答2:

From here

http://developer.apple.com/library/ios/#documentation/StringsTextFonts/Conceptual/CoreText_Programming/Operations/Operations.html

CGFloat GetLineHeightForFont(CTFontRef iFont)
{
    CGFloat lineHeight = 0.0;

    check(iFont != NULL);

    // Get the ascent from the font, already scaled for the font's size
    lineHeight += CTFontGetAscent(iFont);

    // Get the descent from the font, already scaled for the font's size
    lineHeight += CTFontGetDescent(iFont);

    // Get the leading from the font, already scaled for the font's size
    lineHeight += CTFontGetLeading(iFont);

    return lineHeight;
}

To use this, guess a point size, find it's line height (you may or may not care about leading). Then use the ratio between the answer and the height you have to scale the point size. I don't think you're guaranteed that the height will be exactly right -- if you care about it being exact, you have to iterate until it's close enough (use the new size as the new guess).



回答3:

Note: This makes the assumption that your font size will always be smaller than the point size of the CGRect. Adjust methods as necessary to correct for that assumption.

Try this. Works for any of the 3 main methods to create a font. Should be fairly self-explanatory, but increment is the amount you wish to decrement between checks. If you don't care about exact sizing, make that number larger for greater speed. If you do care, make it smaller for higher accuracy.

- (UIFont *)systemFontForRectHeight:(CGFloat)height 
                          increment:(CGFloat)increment {

    UIFont *retVal = nil;
    for (float i = height; i > 0; i = i - increment) {
        retVal = [UIFont systemFontOfSize:i];
        if ([retVal lineHeight] < height) break;
    }
    return retVal;
}
- (UIFont *)boldSystemFontForRectHeight:(CGFloat)height 
                              increment:(CGFloat)increment {

    UIFont *retVal = nil;
    for (float i = height; i > 0; i = i - increment) {
        retVal = [UIFont boldSystemFontOfSize:i];
        if ([retVal lineHeight] < height) break;
    }
    return retVal;
}

- (UIFont *)fontNamed:(NSString *)name 
        forRectHeight:(CGFloat)height 
            increment:(CGFloat)increment {

    UIFont *retVal = nil;
    for (float i = height; i > 0; i = i - increment) {
        retVal = [UIFont fontWithName:name size:i];
        if ([retVal lineHeight] < height) break;
    }
    return retVal;
}