我已经能够使用 Xcode 12b1 和 Swift 5.3 在 Swift 包中成功发布一些图像和 Assets 目录。在 Swift 包中使用自定义 .ttf 文件时,我运气不佳。
我在 list 中加载一个 .ttf 文件,如下所示:
.target(
name: "BestPackage",
dependencies: [],
resources: [
.copy("Resources/Fonts/CustomFont.ttf"),
.process("Resources/Colors.xcassets")
]
),
我注意到 Font
上没有初始化程序键入 SwiftUI 以包含来自模块的 Assets 。例如,这有效:static var PrimaryButtonBackgroundColor: SwiftUI.Color {
Color("Components/Button/Background", bundle: .module)
}
但是,无法指定字体的来源。我希望将其加载到模块中会将其发送到目标中以供使用,但没有这样的运气:static var PrimaryButtonFont: Font {
Font.custom("CustomFont", size: 34)
}
这不会按预期加载字体。我正在研究使用 CoreText api 来尝试欺骗它进行加载,但我觉得应该有一种更简单的方法。有什么建议吗?更新
仍然没有成功,但我能够证明字体确实在模块内
我编写了一个从模块中获取可用字体 URL 的方法,如下所示:
static func fontNames() -> [URL] {
let bundle = Bundle.module
let filenames = ["CustomFont"]
return filenames.map { bundle.url(forResource: $0, withExtension: "ttf")! }
}
在运行时调用此方法并打印结果会产生以下结果:font names: [file:///Users/davidokun/Library/Developer/CoreSimulator/Devices/AFE4ADA0-83A7-46AE-9116-7870B883DBD3/data/Containers/Bundle/Application/800AE766-FB60-4AFD-B57A-0E9F3EACCDB2/BestPackageTesting.app/BestPackage_BestPackage.bundle/CustomFont.ttf]
然后我尝试使用以下方法注册字体以在运行时使用:extension UIFont {
static func register(from url: URL) {
guard let fontDataProvider = CGDataProvider(url: url as CFURL) else {
print("could not get reference to font data provider")
return
}
guard let font = CGFont(fontDataProvider) else {
print("could not get font from coregraphics")
return
}
var error: Unmanaged<CFError>?
guard CTFontManagerRegisterGraphicsFont(font, &error) else {
print("error registering font: \(error.debugDescription)")
return
}
}
}
当我这样称呼它时:fontNames().forEach { UIFont.register(from: $0) }
我收到此错误:error registering font: Optional(Swift.Unmanaged<__C.CFErrorRef>(_value: Error Domain=com.apple.CoreText.CTFontManagerErrorDomain Code=105 "Could not register the CGFont '<CGFont (0x600000627a00): CustomFont>'" UserInfo={NSDescription=Could not register the CGFont '<CGFont (0x600000627a00): CustomFont>', CTFailedCGFont=<CGFont (0x600000627a00): CustomFont>}))
欢迎任何更多想法。
最佳答案
我设法使用 SPM 导入自定义字体,使用这个 SO 答案来帮助 https://stackoverflow.com/a/36871032/5508175
这就是我所做的。创建你的包并添加你的字体。这是我的Package.swift
// swift-tools-version:5.3
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "MyFonts",
products: [
.library(
name: "MyFonts",
targets: ["MyFonts"]),
],
dependencies: [
],
targets: [
.target(
name: "MyFonts",
dependencies: [],
resources: [.process("Fonts")]),
.testTarget(
name: "MyFontsTests",
dependencies: ["MyFonts"]),
]
)
这是我的文件夹结构。我的所有字体都包含在一个名为 Fonts 的文件夹中。内部
MyFonts.swift
我执行以下操作:import Foundation // This is important remember to import Foundation
public let fontBundle = Bundle.module
这使我可以访问包外的 Bundle。接下来,我将包添加到我的项目中。这是一个带有 AppDelegate 的 SwiftUI 项目。
didFinishLaunchingWithOptions
检查字体文件是否可用(可选)所以这是我的 AppDelegate:
import UIKit
import MyFonts
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// This prints out the files that are stored in the MyFont bundle
// Just doing this to check that the fonts are actually in the bundle
if let files = try? FileManager.default.contentsOfDirectory(atPath: fontBundle.bundlePath ){
for file in files {
print(file)
}
}
// This registers the fonts
_ = UIFont.registerFont(bundle: fontBundle, fontName: "FiraCode-Medium", fontExtension: "ttf")
_ = UIFont.registerFont(bundle: fontBundle, fontName: "FiraCode-Bold", fontExtension: "ttf")
_ = UIFont.registerFont(bundle: fontBundle, fontName: "FiraCode-Light", fontExtension: "ttf")
_ = UIFont.registerFont(bundle: fontBundle, fontName: "FiraCode-Regular", fontExtension: "ttf")
_ = UIFont.registerFont(bundle: fontBundle, fontName: "FiraCode-Retina", fontExtension: "ttf")
// This prints out all the fonts available you should notice that your custom font appears in this list
for family in UIFont.familyNames.sorted() {
let names = UIFont.fontNames(forFamilyName: family)
print("Family: \(family) Font names: \(names)")
}
return true
}
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {}
}
// This extension is taken from this SO answer https://stackoverflow.com/a/36871032/5508175
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
}
}
然后在你ContentView
你可以这样做:import SwiftUI
struct ContentView: View {
var body: some View {
VStack(spacing: 20) {
Text("Hello San Francisco")
Text("Hello FiraCode Medium").font(Font.custom("FiraCode-Medium", size: 16))
Text("Hello FiraCode Bold").font(Font.custom("FiraCode-Bold", size: 16))
Text("Hello FiraCode Light").font(Font.custom("FiraCode-Light", size: 16))
Text("Hello FiraCode Regular").font(Font.custom("FiraCode-Regular", size: 16))
Text("Hello FiraCode Retina").font(Font.custom("FiraCode-Retina", size: 16))
}
}
}
这给出了以下结果:注意事项
我还没有在完整的 SwiftUI 应用程序中尝试过这个,但你可以按照显示的教程 here如果您没有 AppDelegate,如何添加 AppDelegate。
显然是
fontBundle
中文件的打印。并且安装的字体是可选的。它们只是用于调试和确保您拥有正确的字体名称文件名可能与您必须用于显示字体的字体名称有很大不同。请参阅我的 SO post关于添加自定义字体:更新
我想知道是否可以创建一个包含在包中的函数并调用它来加载字体。显然是的。
我更新到
MyFonts.swift
到以下:import Foundation
import UIKit
public func registerFonts() {
_ = UIFont.registerFont(bundle: .module, fontName: "FiraCode-Medium", fontExtension: "ttf")
_ = UIFont.registerFont(bundle: .module, fontName: "FiraCode-Bold", fontExtension: "ttf")
_ = UIFont.registerFont(bundle: .module, fontName: "FiraCode-Light", fontExtension: "ttf")
_ = UIFont.registerFont(bundle: .module, fontName: "FiraCode-Regular", fontExtension: "ttf")
_ = UIFont.registerFont(bundle: .module, fontName: "FiraCode-Retina", fontExtension: "ttf")
}
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
}
}
这意味着我可以从 AppDelegate 中删除扩展名,并且不必像在调用 registerFonts()
之前那样在 AppDelegate 中注册每种字体。所以我的
didFinishLaunchingWithOptions
现在看起来像这样:func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// This registers the fonts
registerFonts()
return true
}
请记住,您仍然必须导入您的包。
关于ios - Xcode 12b1 和 Swift 包 : Custom Fonts,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62681206/