精简加载自定义字体
效果图:
核心源码:
UIFont+WDCustomLoader.m 与 UIFont+WDCustomLoader.h
// // UIFont+WDCustomLoader.h // // Created by Walter Da Col on 10/17/13. // Copyright (c) 2013 Walter Da Col (walter.dacol<at>gmail.com) // #import <UIKit/UIKit.h> /** You can use `UIFont+WDCustomLoader` category to load custom fonts for your application without worring about plist or real font names. */ @interface UIFont (WDCustomLoader) /// @name Implicit registration and font loading /** Get `UIFont` object for the selected font file. This method calls `+customFontWithURL:size`. @deprecated @see +customFontWithURL:size: method @param size Font size @param name Font filename without extension @param extension Font filename extension (@"ttf" and @"otf" are supported) @return `UIFont` object or `nil` on errors */ + (UIFont *) customFontOfSize:(CGFloat)size withName:(NSString *)name withExtension:(NSString *)extension; /** Get `UIFont` object for the selected font file (*.ttf or *.otf files). The first call of this method will register the font using `+registerFontFromURL:` method. @see +registerFontFromURL: method @param fontURL Font file absolute url @param size Font size @return `UIFont` object or `nil` on errors */ + (UIFont *) customFontWithURL:(NSURL *)fontURL size:(CGFloat)size; /// @name Explicit registration /** Allow custom fonts registration. With this method you can load all supported font file: ttf, otf, ttc and otc. Font that are already registered, with this library or by system, will not be registered and you will see a warning log. @param fontURL Font file absolute url @return An array of postscript name which represent the file's font(s) or `nil` on errors. (With iOS < 7 as target you will see an empty array for collections) */ + (NSArray *) registerFontFromURL:(NSURL *)fontURL; @end
// // UIFont+WDCustomLoader.m // // Created by Walter Da Col on 10/17/13. // Copyright (c) 2013 Walter Da Col (walter.dacol<at>gmail.com) // #import "UIFont+WDCustomLoader.h" #import <CoreText/CoreText.h> // Feature and deployment target check #if ! __has_feature(objc_arc) #error This file must be compiled with ARC. #endif #if __IPHONE_OS_VERSION_MIN_REQUIRED < 40100 #error This file must be compiled with Deployment Target greater or equal to 4.1 #endif // Activate Xcode only logging #ifdef DEBUG #define UIFontWDCustomLoaderDLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); #else #define UIFontWDCustomLoaderDLog(...) #endif @implementation UIFont (Custom) static CGFloat const kSizePlaceholder = 1.0f; static NSMutableDictionary *appRegisteredCustomFonts = nil; /** Check features for full font collections support @return YES if all features are supported */ + (BOOL) deviceHasFullSupportForFontCollections { return (CTFontManagerCreateFontDescriptorsFromURL != NULL); // 10.6 or 7.0 } /** Inner method for font(s) registration from a file @param fontURL A font URL @return Registration result */ + (BOOL) registerFromURL:(NSURL *)fontURL { CFErrorRef error; BOOL registrationResult = YES; registrationResult = CTFontManagerRegisterFontsForURL((__bridge CFURLRef)fontURL, kCTFontManagerScopeProcess, &error); if (!registrationResult) { UIFontWDCustomLoaderDLog(@"Error with font registration: %@", error); CFRelease(error); return NO; } return YES; } /** Inner method for font registration from a graphic font. @param fontRef A CGFontRef @return Registration result */ + (BOOL) registerFromCGFont:(CGFontRef)fontRef { CFErrorRef error; BOOL registrationResult = YES; registrationResult = CTFontManagerRegisterGraphicsFont(fontRef, &error); if (!registrationResult) { UIFontWDCustomLoaderDLog(@"Error with font registration: %@", error); CFRelease(error); return NO; } return YES; } + (NSArray *) registerFontFromURL:(NSURL *)fontURL { // Dictionary creation static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ appRegisteredCustomFonts = [NSMutableDictionary new]; }); // Result NSArray *fontPSNames = nil; // Critical section @synchronized(appRegisteredCustomFonts) { // Check if this library knows this url fontPSNames = [[appRegisteredCustomFonts objectForKey:fontURL] copy]; if (fontPSNames == nil) { // Check features if ([UIFont deviceHasFullSupportForFontCollections]) { // Retrieve font descriptors from ttf, otf, ttc and otc files NSArray *fontDescriptors = (__bridge_transfer NSArray *)(CTFontManagerCreateFontDescriptorsFromURL((__bridge CFURLRef)fontURL)); // Check errors if (fontDescriptors) { // Check how many fonts are already registered (or have the // same name of another font) NSMutableArray *verifiedFontPSNames = [NSMutableArray new]; for (NSDictionary *fontDescriptor in fontDescriptors) { NSString *fontPSName = [fontDescriptor objectForKey:@"NSFontNameAttribute"]; if (fontPSName) { if ([UIFont fontWithName:fontPSName size:kSizePlaceholder]) { UIFontWDCustomLoaderDLog(@"Warning with font registration: Font '%@' already registered",fontPSName); } [verifiedFontPSNames addObject:fontPSName]; } } fontPSNames = [NSArray arrayWithArray:verifiedFontPSNames]; // At least one if ([fontPSNames count] > 0) { // If registration went ok if ([UIFont registerFromURL:fontURL]) { // Add url to this library [appRegisteredCustomFonts setObject:fontPSNames forKey:fontURL]; } else { fontPSNames = nil; } } else { // [fontPSNames count] <= 0 UIFontWDCustomLoaderDLog(@"Warning with font registration: All fonts in '%@' are already registered", fontURL); } } else { // CTFontManagerCreateFontDescriptorsFromURL fail UIFontWDCustomLoaderDLog(@"Error with font registration: File '%@' is not a Font", fontURL); fontPSNames = nil; } } else { // [UIFont deviceHasFullSupportForFontCollections] fail // Read data NSError *error; NSData *fontData = [NSData dataWithContentsOfURL:fontURL options:NSDataReadingUncached error:&error]; // Check data creation if (fontData) { // Load font CGDataProviderRef fontDataProvider = CGDataProviderCreateWithCFData((CFDataRef)fontData); CGFontRef loadedFont = CGFontCreateWithDataProvider(fontDataProvider); // Check font if (loadedFont != NULL) { // Prior to iOS7 is not easy to retrieve names from font collections // But is possible to register collections NSSet *singleFontValidExtensions = [NSSet setWithArray:@[@"ttf", @"otf"]]; if ([singleFontValidExtensions containsObject:[fontURL pathExtension]]) { // Read name fontPSNames = @[(__bridge_transfer NSString *)(CGFontCopyPostScriptName(loadedFont))]; // Check if registration is required if ([UIFont fontWithName:fontPSNames[0] size:kSizePlaceholder] == nil) { // If registration went ok if ([UIFont registerFromCGFont:loadedFont]) { // Add url to this library [appRegisteredCustomFonts setObject:fontPSNames forKey:fontURL]; } else { fontPSNames = nil; } } else { UIFontWDCustomLoaderDLog(@"Warning with font registration: All fonts in '%@' are already registered", fontURL); } } else { // Is a collection //TODO find a way to read names fontPSNames = @[]; // Revert to url registration which allow collections // If registration went ok if ([UIFont registerFromURL:fontURL]) { // Add url to this library [appRegisteredCustomFonts setObject:fontPSNames forKey:fontURL]; } else { fontPSNames = nil; } } } else { // CGFontCreateWithDataProvider fail UIFontWDCustomLoaderDLog(@"Error with font registration: File '%@' is not a Font", fontURL); fontPSNames = nil; } // Release CGFontRelease(loadedFont); CGDataProviderRelease(fontDataProvider); } else { UIFontWDCustomLoaderDLog(@"Error with font registration: URL '%@' cannot be read with error: %@", fontURL, error); fontPSNames = nil; } } } } return fontPSNames; } + (UIFont *) customFontWithURL:(NSURL *)fontURL size:(CGFloat)size { // Only single font with this method NSSet *singleFontValidExtensions = [NSSet setWithArray:@[@"ttf", @"otf"]]; if (![singleFontValidExtensions containsObject:[fontURL pathExtension]]) { UIFontWDCustomLoaderDLog(@"Only ttf or otf files are supported by this method"); return nil; } NSArray *fontPSNames = [UIFont registerFontFromURL:fontURL]; if (fontPSNames == nil) { UIFontWDCustomLoaderDLog(@"Invalid Font URL: %@", fontURL); return nil; } if ([fontPSNames count] != 1) { UIFontWDCustomLoaderDLog(@"Font collections not supported by this method"); return nil; } return [UIFont fontWithName:fontPSNames[0] size:size]; } + (UIFont *) customFontOfSize:(CGFloat)size withName:(NSString *)name withExtension:(NSString *)extension { // Get url for font resource NSURL *fontURL = [[[NSBundle mainBundle] URLForResource:name withExtension:extension] absoluteURL]; return [UIFont customFontWithURL:fontURL size:size]; } @end
以下源码都是本人在上述源码基础上封装的:
FontInfo.h 与 FontInfo.m
// // FontInfo.h // GCD // // Created by YouXianMing on 14-9-21. // Copyright (c) 2014年 YouXianMing. All rights reserved. // #import <Foundation/Foundation.h> @interface FontInfo : NSObject + (NSDictionary *)customFontNameList; + (NSDictionary *)systomFontNameList; + (void)registerFont:(NSString *)fontPath withName:(NSString *)name; @end
// // FontInfo.m // GCD // // Created by YouXianMing on 14-9-21. // Copyright (c) 2014年 YouXianMing. All rights reserved. // #import "FontInfo.h" #import "UIFont+WDCustomLoader.h" static NSMutableDictionary *customFontDictionary = nil; // 自己加载的字体信息 static NSMutableDictionary *systemFontDictionary = nil; // 系统字体信息 @implementation FontInfo + (void)initialize { if (self == [FontInfo class]) { customFontDictionary = [[NSMutableDictionary alloc] init]; systemFontDictionary = [[NSMutableDictionary alloc] init]; // 获取系统字体族 [FontInfo getSystemFontList]; } } + (void)getSystemFontList { NSArray *familyNames = [UIFont familyNames]; for( NSString *familyName in familyNames) { NSArray *fontNames = [UIFont fontNamesForFamilyName:familyName]; [systemFontDictionary setObject:fontNames forKey:familyName]; } } + (void)registerFont:(NSString *)fontPath withName:(NSString *)name { NSArray *nameArray = [UIFont registerFontFromURL:[NSURL fileURLWithPath:fontPath]]; [customFontDictionary setObject:nameArray forKey:name]; } + (NSDictionary *)customFontNameList { return [NSDictionary dictionaryWithDictionary:customFontDictionary]; } + (NSDictionary *)systomFontNameList { return [NSDictionary dictionaryWithDictionary:systemFontDictionary]; } @end
UIFont+Custom.h 与 UIFont+Custom.m
// // UIFont+Custom.h // GCD // // Created by YouXianMing on 14-9-21. // Copyright (c) 2014年 YouXianMing. All rights reserved. // #import <UIKit/UIKit.h> @interface UIFont (CustomFont) + (void)registerFontFamily:(NSString *)fontPath withName:(NSString *)name; + (NSDictionary *)systomAllFontsFamilyInfo; @end
// // UIFont+Custom.m // GCD // // Created by YouXianMing on 14-9-21. // Copyright (c) 2014年 YouXianMing. All rights reserved. // #import "UIFont+CustomFont.h" #import "FontInfo.h" #ifdef DEBUG #define UIFontCustomFontDLog(fmt, ...) NSLog((@"%@[%d]:%s:" fmt),[[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, __func__, ##__VA_ARGS__); #else #define UIFontCustomFontDLog(...) #endif @implementation UIFont (CustomFont) + (void)registerFontFamily:(NSString *)fontPath withName:(NSString *)name { if (fontPath == nil) { UIFontCustomFontDLog(@"[警告]fontPath为空"); return; } [FontInfo registerFont:fontPath withName:name]; } + (NSDictionary *)systomAllFontsFamilyInfo { return [FontInfo systomFontNameList]; } @end
NSString+CustomFont.h 与 NSString+CustomFont.m
// // NSString+CustomFont.h // GCD // // Created by YouXianMing on 14-9-21. // Copyright (c) 2014年 YouXianMing. All rights reserved. // #import <Foundation/Foundation.h> /* NSString值都为字体族名字 */ /* 经典字体家族 "Helvetica Neue" = ( "HelveticaNeue-BoldItalic", "HelveticaNeue-Light", "HelveticaNeue-Italic", "HelveticaNeue-UltraLightItalic", "HelveticaNeue-CondensedBold", "HelveticaNeue-MediumItalic", "HelveticaNeue-Thin", "HelveticaNeue-Medium", "HelveticaNeue-ThinItalic", "HelveticaNeue-LightItalic", "HelveticaNeue-UltraLight", "HelveticaNeue-Bold", HelveticaNeue, "HelveticaNeue-CondensedBlack" ); */ @interface NSString (CustomFont) - (NSString *)customFontFamilyName; - (NSString *)customFontFamilyNameAtIndex:(NSInteger)index; - (NSArray *)customFontInfo; - (NSString *)systemFontFamilyName; - (NSString *)systemFontFamilyNameIndex:(NSInteger)index; - (NSArray *)systemFontInfo; @end
// // NSString+CustomFont.m // GCD // // Created by YouXianMing on 14-9-21. // Copyright (c) 2014年 YouXianMing. All rights reserved. // #import "NSString+CustomFont.h" #import "FontInfo.h" @implementation NSString (CustomFont) #pragma public - (NSString *)customFontFamilyName { return [self fontFamilyName:self customFontIndex:0]; } - (NSString *)customFontFamilyNameAtIndex:(NSInteger)index { return [self fontFamilyName:self customFontIndex:index]; } - (NSArray *)customFontInfo { NSDictionary *fontDic = [FontInfo customFontNameList]; if (self) { return fontDic[self]; } else { return nil; } } - (NSString *)systemFontFamilyName { return [self fontFamilyName:self systemFontIndex:0]; } - (NSString *)systemFontFamilyNameIndex:(NSInteger)index { return [self fontFamilyName:self systemFontIndex:index]; } - (NSArray *)systemFontInfo { NSDictionary *fontDic = [FontInfo systomFontNameList]; if (self) { return fontDic[self]; } else { return nil; } } #pragma private - (NSString *)fontFamilyName:(NSString *)fontName customFontIndex:(NSInteger)index { if (fontName == nil) { return nil; } NSDictionary *fontDic = [FontInfo customFontNameList]; NSArray *fontIndex = fontDic[fontName]; if (fontIndex) { return fontIndex[index]; } else { return nil; } } - (NSString *)fontFamilyName:(NSString *)fontName systemFontIndex:(NSInteger)index { if (fontName == nil) { return nil; } NSDictionary *fontDic = [FontInfo systomFontNameList]; NSArray *fontIndex = fontDic[fontName]; if (fontIndex) { return fontIndex[index]; } else { return nil; } } @end
以下是使用源码:
// // RootViewController.m // GCD // // Created by YouXianMing on 14-9-21. // Copyright (c) 2014年 YouXianMing. All rights reserved. // #import "RootViewController.h" #import "NSString+CustomFont.h" #import "UIFont+CustomFont.h" @interface RootViewController () @end @implementation RootViewController - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor blackColor]; // 注册自定义字体 [UIFont registerFontFamily:[@"新蒂小丸子小学版.ttf" bundleFile] withName:@"新蒂小丸子小学版"]; // 显示 UILabel *label_1 = [[UILabel alloc] initWithFrame:CGRectMake(50, 50, 200, 40)]; label_1.text = @"游贤明"; label_1.textColor = [UIColor redColor]; label_1.textAlignment = NSTextAlignmentCenter; label_1.font = [UIFont fontWithName:[@"新蒂小丸子小学版" customFontFamilyName] size:30.f]; [self.view addSubview:label_1]; UILabel *label_2 = [[UILabel alloc] initWithFrame:CGRectMake(50, 100, 200, 40)]; label_2.text = @"YouXianMing"; label_2.textColor = [UIColor whiteColor]; label_2.textAlignment = NSTextAlignmentCenter; label_2.font = [UIFont fontWithName:[@"Helvetica Neue" systemFontFamilyNameIndex:1] size:18.f]; [self.view addSubview:label_2]; // 打印字体族信息 NSLog(@"%@", [@"新蒂小丸子小学版" customFontInfo]); NSLog(@"%@", [@"Helvetica Neue" systemFontFamilyNameIndex:1]); } @end
使用注意事项: