精简加载自定义字体
效果图:
核心源码:
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
使用注意事项: