On an iPhone how do I calculate the size of a character in pixels for a given point size?
Our graphic artist was very specific on certain devices to use pixel sizes instead of point size. The function below will return a font based on pixel size. It uses a brute force method to find the closet font, but then caches the results so next time the return will be very fast. I always appreciate comments on how this code could be made better. I use this function as a static class member in class called utils. You can easily paste into any class you are using. Hope it is of some help.
/** return a font as close to a pixel size as possible
example:
UIFont *font = [Utils fontWithName:@"HelveticaNeue-Medium" sizeInPixels:33];
@param fontName name of font same as UIFont fontWithName
@param sizeInPixels size in pixels for font
*/
+(UIFont *) fontWithName:(NSString *) fontName sizeInPixels:(CGFloat) pixels {
static NSMutableDictionary *fontDict; // to hold the font dictionary
if ( fontName == nil ) {
// we default to @"HelveticaNeue-Medium" for our default font
fontName = @"HelveticaNeue-Medium";
}
if ( fontDict == nil ) {
fontDict = [ @{} mutableCopy ];
}
// create a key string to see if font has already been created
//
NSString *strFontHash = [NSString stringWithFormat:@"%@-%f", fontName , pixels];
UIFont *fnt = fontDict[strFontHash];
if ( fnt != nil ) {
return fnt; // we have already created this font
}
// lets play around and create a font that falls near the point size needed
CGFloat pointStart = pixels/4;
CGFloat lastHeight = -1;
UIFont * lastFont = [UIFont fontWithName:fontName size:.5];\
NSMutableDictionary * dictAttrs = [ @{ } mutableCopy ];
NSString *fontCompareString = @"Mgj^";
for ( CGFloat pnt = pointStart ; pnt < 1000 ; pnt += .5 ) {
UIFont *font = [UIFont fontWithName:fontName size:pnt];
if ( font == nil ) {
NSLog(@"Unable to create font %@" , fontName );
NSAssert(font == nil, @"font name not found in fontWithName:sizeInPixels" ); // correct the font being past in
}
dictAttrs[NSFontAttributeName] = font;
CGSize cs = [fontCompareString sizeWithAttributes:dictAttrs];
CGFloat fheight = cs.height;
if ( fheight == pixels ) {
// that will be rare but we found it
fontDict[strFontHash] = font;
return font;
}
if ( fheight > pixels ) {
if ( lastFont == nil ) {
fontDict[strFontHash] = font;
return font;
}
// check which one is closer last height or this one
// and return the user
CGFloat fc1 = fabs( fheight - pixels );
CGFloat fc2 = fabs( lastHeight - pixels );
// return the smallest differential
if ( fc1 < fc2 ) {
fontDict[strFontHash] = font;
return font;
} else {
fontDict[strFontHash] = lastFont;
return lastFont;
}
}
lastFont = font;
lastHeight = fheight;
}
NSAssert( false, @"Hopefully should never get here");
return nil;
}