如何将CGFontRef转换为UIFont?

19

我想为一个UILabel使用自定义字体。自定义字体是从文件中加载的:

NSString *fontPath = ... ; // a TTF file in iPhone Documents folder
CGDataProviderRef fontDataProvider = CGDataProviderCreateWithFilename([fontPath UTF8String]);
CGFontRef customFont = CGFontCreateWithDataProvider(fontDataProvider);
CGDataProviderRelease(fontDataProvider); 

我该如何将 CGFontRef 转换为 UIFont,以便在 [UILabel setFont:] 中使用?


2
你需要支持哪个iOS版本?你可以通过编辑Info.plist文件来加载捆绑的字体,将其作为UIFont实例加载。 - Costique
1
我不确定如何将CGFontRef转换为UIFont,但您可以创建一个UILabel的子类,该子类接受CGFontRef。请参考此博客以了解如何实现。 - Joel Kravets
@Costique iOS 4.3或更高版本都可以。字体是用户在下载应用程序后添加的,因此我无法预设Info.plist。 - ohho
6个回答

18

您无法直接将CGFontRef转换为UIFont,但是您可以使用CTFontManagerRegisterGraphicsFont注册CGFontRef,然后创建相应的UIFont

NSString* fpath = [documentsDirectory stringByAppendingPathComponent:@"custom_font_file_name.ttf"];
CGDataProviderRef fontDataProvider = CGDataProviderCreateWithFilename([fpath UTF8String]);
CGFontRef customFont = CGFontCreateWithDataProvider(fontDataProvider);
CGDataProviderRelease(fontDataProvider);
NSString *fontName = (__bridge NSString *)CGFontCopyFullName(customFont);
CFErrorRef error;
CTFontManagerRegisterGraphicsFont(customFont, &error);
CGFontRelease(customFont);
UIFont* uifont = [UIFont fontWithName:fontName size:12];

我收到了这个错误信息:无法加载字体:“操作无法完成。(com.apple.coretext 错误105 - 无法注册 CGFont '<CGFont (0x89919a0): Melville>')” - Durgaprasad
文档目录.. "使用了未声明的标识符 'documentsDirectory'... 你是不是想说...???" - Morkrom

17

Conrad的答案很接近但不太正确。你需要提供UIFont的PostScript名称,而不是完整名称。

NSString *fontName = (NSString *)CGFontCopyPostScriptName(fontRef);
UIFont *font = [UIFont fontWithName:fontName size:someSize]

3
请注意,CGFontCopyPostScriptName 方法会分配并返回一个 CFStringRef 类型的值,你需要稍后调用 CFRelease 函数释放它。将此方法的返回值强制转换为 NSString 可能会影响代码的可读性,因此不建议这样做。 - Grzegorz Adam Hankiewicz

5

CTFontRefUIFonttoll-free bridged的,因此您可以将CGFont转换为CTFont,然后将其转换为UIFont

CTFontRef ctFont = CTFontCreateWithGraphicsFont(cgFont, pointSize, NULL, NULL);
UIFont *uiFont = CFBridgingRelease(ctFont);

3

原则上,它们不是直接可转换的。一个简单的原因是UIFont封装了字体大小,而CGFont是大小无关的(大小是图形上下文的属性;请参见CGContextSetFontSize())。

假设您已经确定了所需的字体大小,那么您应该能够像这样做:

NSString *fontName = (NSString *)CGFontCopyFullName(someCGFontRef);
UIFont *font = [UIFont fontWithName:fontName size:someSize];
[fontName release];

我实际上没有测试过这个,但它应该可以工作(可能需要一些小的添加)。我相信CGFont和UIFont之间有一个名称对应关系 - 但如果没有,这显然不会起作用。


2
您可以将CGFont转换为CTFont,但不幸的是两者都不能得到UIFont。以下是获取UIFont的方法:请求系统字体或按其PostScript名称请求字体。因此,对于UILabel中的自定义提供的字体,建议使用后者。
如果您事先知道应用程序将使用的字体文件,可以将其添加到捆绑包中,并使用UIFont的+fontWithName:size:方法加载它,因为UIFont会搜索具有该PostScript名称的字体文件的捆绑包。
例如,TrueType字体文件“VeraMono.ttf”具有PostScript名称“Bitstream Vera Sans Mono”,因此可以像下面这样将其加载到UILabel中: label.font = [UIFont fontWithName:@"Bitstream Vera Sans Mono" size:12];
要以非动态方式获取PostScript名称,请使用字体工具,或者在上面的情况下,PostScript名称恰好等于Finder>获取信息显示的“完整名称”。
但是,在您不一定知道字体的PostScript名称的情况下(例如支持用户定义的字体),也许您可以将文件名加载到NSData并“grep”其PostScript名称...
祝你好运,

感谢您的解释。您的回答与Josh Brown的答案一起,帮助了我4年后! - Coach Roebuck

0

更新为 Swift 4,以获取 PostScript 名称(其中 font 是 CGFont):

let fontName = font?.postScriptName as String?
textLabel.font = UIFont(name: fontName!, size: 17)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接