我想在Cocoapod中使用自定义字体,但是我找不到有关在静态库中使用自定义字体的任何信息。由于没有info.plist文件,因此无法告诉应用程序使用哪种字体。
有什么好的建议吗?
有一种方法可以在不向plist文件添加任何内容的情况下使用自定义字体。
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSURL *fontURL = [bundle URLForResource:<#fontName#> withExtension:@"otf"/*or TTF*/];
NSData *inData = [NSData dataWithContentsOfURL:fontURL];
CFErrorRef error;
CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)inData);
CGFontRef font = CGFontCreateWithDataProvider(provider);
if (!CTFontManagerRegisterGraphicsFont(font, &error)) {
CFStringRef errorDescription = CFErrorCopyDescription(error);
NSLog(@"Failed to load font: %@", errorDescription);
CFRelease(errorDescription);
}
CFSafeRelease(font);
CFSafeRelease(provider);
CFSafeRelease
函数才能使其正常工作。void CFSafeRelease(CFTypeRef cf) {
if (cf != NULL) {
CFRelease(cf);
}
}
来源:动态加载iOS字体。
Swift等效代码:
extension UIFont {
static func registerFont(bundle: Bundle, fontName: String, fontExtension: String) -> Bool {
guard let fontURL = bundle.url(forResource: fontName, withExtension: fontExtension) else {
fatalError("Couldn't find font \(fontName)")
}
guard let fontDataProvider = CGDataProvider(url: fontURL as CFURL) else {
fatalError("Couldn't load data from the font \(fontName)")
}
guard let font = CGFont(fontDataProvider) else {
fatalError("Couldn't create font from data")
}
var error: Unmanaged<CFError>?
let success = CTFontManagerRegisterGraphicsFont(font, &error)
guard success else {
print("Error registering font: maybe it was already registered.")
return false
}
return true
}
}
如果您在2018年或之后找到了这篇文章,我有两个步骤让定制字体能够在界面构建器支持下(XCode 9)工作:
将您的字体添加到框架的资源包中(在.podspec文件中)
s.resources = "PodName/**/*.{ttf}"
使用Adam上面的答案在运行时加载字体
#import <CoreText/CoreText.h>
void CFSafeRelease(CFTypeRef cf) { // redefine this
if (cf != NULL) {
CFRelease(cf);
}
}
+ (void) loadFonts {
NSBundle *frameworkBundle = [NSBundle bundleForClass:self.classForCoder];
NSURL *bundleURL = [[frameworkBundle resourceURL] URLByAppendingPathComponent:@"PodName.bundle"];
NSBundle *bundle = [NSBundle bundleWithURL:bundleURL];
NSURL *fontURL = [bundle URLForResource:@"HindMadurai-SemiBold" withExtension:@"ttf"];
NSData *inData = [NSData dataWithContentsOfURL:fontURL];
CFErrorRef error;
CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)inData);
CGFontRef font = CGFontCreateWithDataProvider(provider);
if (!CTFontManagerRegisterGraphicsFont(font, &error)) {
CFStringRef errorDescription = CFErrorCopyDescription(error);
NSLog(@"Failed to load font: %@", errorDescription);
CFRelease(errorDescription);
}
CFSafeRelease(font);
CFSafeRelease(provider);
}
执行 pod install 命令
如果我理解正确的话,您正在尝试通过Cocoapod提供字体,并且希望包括该Pod的iOS应用程序能够使用您的自定义字体。
这个post_install
挂钩似乎有效:
Pod::Spec.new do |s|
# ...
s.resources = "Resources/*.otf"
# ...
s.post_install do |library_representation|
require 'rexml/document'
library = library_representation.library
proj_path = library.user_project_path
proj = Xcodeproj::Project.new(proj_path)
target = proj.targets.first # good guess for simple projects
info_plists = target.build_configurations.inject([]) do |memo, item|
memo << item.build_settings['INFOPLIST_FILE']
end.uniq
info_plists = info_plists.map { |plist| File.join(File.dirname(proj_path), plist) }
resources = library.file_accessors.collect(&:resources).flatten
fonts = resources.find_all { |file| File.extname(file) == '.otf' || File.extname(file) == '.ttf' }
fonts = fonts.map { |f| File.basename(f) }
info_plists.each do |plist|
doc = REXML::Document.new(File.open(plist))
main_dict = doc.elements["plist"].elements["dict"]
app_fonts = main_dict.get_elements("key[text()='UIAppFonts']").first
if app_fonts.nil?
elem = REXML::Element.new 'key'
elem.text = 'UIAppFonts'
main_dict.add_element(elem)
font_array = REXML::Element.new 'array'
main_dict.add_element(font_array)
else
font_array = app_fonts.next_element
end
fonts.each do |font|
if font_array.get_elements("string[text()='#{font}']").empty?
font_elem = REXML::Element.new 'string'
font_elem.text = font
font_array.add_element(font_elem)
end
end
doc.write(File.open(plist, 'wb'))
end
end
这个钩子会查找用户项目,在第一个目标中(通过向CocoaPods请求真实目标,您可能可以完成此解决方案),它会查找其Info.plist
文件(通常只有一个)。最后,如果没有找到钩子则创建UIAppFonts
键的文件,并在字体名称未填充数组的情况下将其填充。
pod spec lint
验证规范的某些部分无效了。但是在安装后它能够正常工作并添加自定义字体,有什么建议吗? - Ikhsan AssaatSwift 5实现
我通过在我的Cocoapod中创建下面的类来解决这个问题,然后只需从我的主应用程序的AppDelegate.swift
调用CustomFonts.loadAll()
即可。之后,我可以在我的应用程序中像这样使用字体:
let myFont = CustomFonts.Style.regular.font
请注意,Style
枚举不是必需的,只是一种方便的分离关注点的方式。您也可以直接调用:
let myFont = UIFont(name: "SourceSansPro-SemiBold", size: 14)
import CoreText
public class CustomFonts: NSObject {
public enum Style: CaseIterable {
case mono
case regular
case semibold
public var value: String {
switch self {
case .mono: return "SourceCodePro-Medium"
case .regular: return "SourceSansPro-Regular"
case .semibold: return "SourceSansPro-SemiBold"
}
}
public var font: UIFont {
return UIFont(name: self.value, size: 14) ?? UIFont.init()
}
}
// Lazy var instead of method so it's only ever called once per app session.
public static var loadFonts: () -> Void = {
let fontNames = Style.allCases.map { $0.value }
for fontName in fontNames {
loadFont(withName: fontName)
}
return {}
}()
private static func loadFont(withName fontName: String) {
guard
let bundleURL = Bundle(for: self).url(forResource: "[CococpodName]", withExtension: "bundle"),
let bundle = Bundle(url: bundleURL),
let fontURL = bundle.url(forResource: fontName, withExtension: "ttf"),
let fontData = try? Data(contentsOf: fontURL) as CFData,
let provider = CGDataProvider(data: fontData),
let font = CGFont(provider) else {
return
}
CTFontManagerRegisterGraphicsFont(font, nil)
}
}
嗯,我不确定这是否是一个答案,但你也可以看一下CocoaPod,其中包含所需的字体,例如: https://github.com/parakeety/GoogleFontsiOS。
该库包含许多字体,我需要Chivo,因此我添加了pod 'GoogleFontsiOS/Chivo',并使用它来替代自己编写的字体加载代码。
CTFontManagerRegisterFontsForURL
函数让生活更轻松。
registerFont
将在何时何地被调用? - h.and.h