UIFontとCTFontは、iOSでフォントを扱うためのクラスです。UIFontはUIKitに属し、UILabelやUITextViewでの高レベルなテキスト設定に使用されます。CTFontはCore Textに属し、グリフとメトリクスを完全に制御できる低レベルなレンダリングに使用されます。Apple Developer Documentationによると、UIFontは標準UIコンポーネントの90%で使用され、CTFontはカスタムテキストエンジンやエディターで使用されています。両クラスは同じフォントを異なる抽象化レベルで表現します。
重要なポイント
UIFontは、UIコンポーネント(UILabel、UITextView、UITextField)でテキストを表示するためのフォントを表すUIKitクラスです。サイズ、ウェイト、スタイルを指定してシステムフォントやカスタムフォントを取得するためのシンプルなインターフェースを提供します。UIFontではカーニング、リガチャー、OpenType機能を直接制御できません。そのためにはCore Textを使用します。
CTFontは、フォントデータへの低レベルアクセスを提供するCore Textタイプ(CTFontRef)です。CTFontはレンダリングのためにCore Graphicsと直接連携し、代替グリフ、リガチャー、可変フォントを含むすべてのOpenTypeおよびTrueType機能をサポートします。CTFontはUIKit内部でUIFontのレンダリングに使用されますが、カスタム描画のために直接利用することもできます。
UIFontとCTFontはToll-Free Bridgingをサポートしています。これは追加コストなしでの型間変換です。SwiftとObjective-Cでは、UIFont as CTFontまたはCTFont as UIFontのキャストが可能です。これにより、フォントデータをコピーすることなく、設定には高レベルのUIKit APIを、レンダリングには低レベルのCore Textを使用できます。
両クラスはフォントの特性(名前、サイズ、ウェイト、スタイル、変換行列)を記述するためにUIFontDescriptor(UIKit)/ CTFontDescriptor(Core Text)を使用します。ディスクリプタは属性の辞書であり、既存のフォントを基に新しいフォントを作成するために変更できます。例えば、ディスクリプタにtraitItalicを追加して、同じフォントのイタリック版を取得できます。
UIFontはフォントを作成するためのいくつかのファクトリメソッドを提供します。systemFont(ofSize:)はシステムフォントSan Francisco(iOS)またはHelvetica(古いバージョン)を返します。boldSystemFont、italicSystemFontは特定のスタイルのバリアントです。preferredFont(forTextStyle:)は指定されたスタイル(.headline、.body、.caption1、.footnote)のDynamic Typeフォントを返します。これらのフォントは、システムのテキストサイズ設定が変更されると自動的に拡大縮小されます。
カスタムフォントを読み込むには、フォントのPostScript名を使用してUIFont(name:size:)を使用します。フォントは事前にInfo.plistに追加され、アプリのバンドルに含まれている必要があります。Appleによると、標準的なUIコンポーネントにはすべてUIFontを使用し、カスタムレンダリングが必要な場合にのみCTFontに切り替えることを推奨しています。
Dynamic TypeはiOS 7で導入された適応型フォントシステムです。ユーザーは設定で好みのテキストサイズ(極小から極大まで)を選択します。UIFont.preferredFontは自動的に適切なサイズのフォントを返します。正しく動作させるには、すべてのUILabelでadjustsFontForContentSizeCategory = trueを設定する必要があります。Dynamic Typeはアクセシビリティ準拠のために必須です。
UIFontDescriptorを使用すると、ゼロから新しいインスタンスを作成せずにフォント属性を変更できます。addingAttributes(_:)、withSymbolicTraits(_:)、withFamily(_:)メソッドは、変更されたパラメーターで新しいディスクリプタを返します。これはフォントバリアントを取得するのに便利です。PostScript名を知らなくても、システムフォントにtraitBoldを追加して太字版を取得できます。
CTFont(CTFontRef)は低レベルなフォント操作のためのCore Textタイプです。CTFontCreateWithName、CTFontCreateWithFontDescriptor、CTFontCreateCopyWithAttributesによって作成されます。各関数は、指定されたインターフェース、サイズ、オプションの属性を持つフォントを返します。CTFontは、drawRectを介してカスタムUIViewにテキストをレンダリングするためにCore Graphicsで使用されます。
CTFontはUIFontでは利用できないメトリクスへのアクセスを提供します。CTFontGetGlyphsForCharactersは指定された文字のグリフ配列を返し、CTFontGetAdvancesForGlyphsは各グリフの幅を、CTFontGetBoundingBoxはグリフの境界を返します。これらはカスタムテキストレイアウト(カラム、回転、ラッピング)を構築するために必要です。
CTFontGetAscent、CTFontGetDescent、CTFontGetLeadingは垂直フォントメトリクスを返します。CTFontGetUnitsPerEmはem-squareあたりのユニット数で、比率計算に使用されます。CTFontGetGlyphCountはフォント内のグリフ総数です。これらのデータは、各文字の正確な位置決めが必要な印刷タイポグラフィやカスタムレイアウトに重要です。
CTFontはOpenType機能をサポートしています。CTFontCopyFeaturesは利用可能なフォント機能(リガチャー、代替文字、カーニング)の辞書を返し、CTFontEnableFeatureは特定のオプションを有効にします。可変フォントはCTFontCopyVariationとCTFontCreateCopyWithVariationを介して設定され、weight、width、slantを連続的な範囲で変更できます。
SwiftでのUIFontの作成は、ファクトリメソッドのいずれか、または名前による直接初期化によって行われます。最も一般的な方法は、システムフォントにはsystemFont(ofSize:weight:)、Dynamic TypeにはpreferredFont(forTextStyle:)を使用することです。カスタムフォントには、PostScript名を指定してUIFont(name:size:)を使用します。
UIFont.systemFont(ofSize:weight:)はUIFont.Weight(.ultraLightから.blackまで)を受け入れます。このメソッドは対応するウェイトのSan Franciscoシステムフォントを返します。UIFont.monospacedSystemFont、UIFont.monospacedDigitSystemFontはコードと数字用の等幅フォントを返します。すべてのシステムフォントは自動的にDynamic Typeをサポートします。
let regularFont = UIFont.systemFont(ofSize: 16, weight: .regular)
let boldFont = UIFont.systemFont(ofSize: 16, weight: .bold)
let headlineFont = UIFont.preferredFont(forTextStyle: .headline)
let monoFont = UIFont.monospacedSystemFont(ofSize: 14, weight: .regular)
label.font = headlineFont
各フォントはUILabelのfontプロパティに直接割り当てるか、NSFontAttributeNameを介してNSAttributedStringで使用できます。システムフォントはiOSによってキャッシュされるため、システムフォントを再作成してもオーバーヘッドは発生しません。
カスタムフォントを使用するには、TTFまたはOTFファイルをプロジェクトバンドルに追加し、Info.plist(UIAppFonts)で指定します。フォントのPostScript名は、UIFont.familyNamesとUIFont.fontNames(forFamilyName:)で確認できます。登録後、フォントはアプリ内のどこからでもUIFont(name:size:)で利用可能になります。
// すべてのフォントファミリー名を取得
for family in UIFont.familyNames {
let names = UIFont.fontNames(forFamilyName: family)
print("\(family): \(names)")
}
// カスタムフォントを読み込む
if let customFont = UIFont(name: "MyCustomFont-Regular", size: 18) {
label.font = customFont
}
フォント名が正しく指定されていない場合、UIFont(name:size:)はnilを返します。デバッグ中にUIFont.familyNamesとUIFont.fontNames(forFamilyName:)を介してすべての利用可能なフォント名を出力し、フォントが正しく登録されていることを確認することをお勧めします。
カスタムフォントの読み込みは2つの方法で可能です。Info.plist(UIAppFonts)を介した静的登録と、CTFontManagerRegisterGraphicsFontを介した動的登録です。最初の方法はより簡単で、アプリ起動後すぐにフォントが利用可能になります。2番目の方法は、ネットワークからダウンロードしたフォントやオンデマンドリソースに使用されます。
動的登録はオンデマンドリソースに便利です。アプリに20以上のフォントが含まれている場合、それらすべてを初期バンドルから除外し、最初の使用時にダウンロードできます。CTFontManagerRegisterFontsForURLsは指定されたURLからフォントを登録します。登録後、フォントは通常どおりUIFont(name:size:)で利用可能になります。
Core Textを介したカスタムレンダリングには、フォントのPostScript名を使用してCTFontCreateWithNameを使用します。UIFontとの違いは、CTFontは変換行列(CTFontCreateWithNameAndOptions)を指定して作成でき、傾斜、X軸スケーリング、回転などの歪んだフォントを作成できることです。これはアフィン変換を使用しないUIFontでは利用できません。
// スキュー行列でCTFontを作成
var matrix = CGAffineTransform(a: 1, b: 0, c: 0.2, d: 1, tx: 0, ty: 0)
let ctFont = CTFontCreateWithName(
"Helvetica" as CFString,
24, &matrix)
// UIFontでToll-Free Bridgingを使用
let uiFont = ctFont as UIFont
label.font = uiFont
変換行列を使用すると、別のフォントファイルなしでイタリックバリアントを作成できます。パラメータc(skew)は文字に傾斜を追加します。行列はフォントを水平方向に拡大縮小することもでき、1つのフォントのコンデンス版やエクスパンド版を作成できます。
UIFontとCTFontの主な違いは抽象化のレベルです。UIFontは一般的なタスク(システムフォントの取得、サイズ変更、UILabelへの適用)のためのシンプルなAPIを提供します。CTFontはフォントの完全な制御(グリフ、メトリクス、OpenTypeテーブル、可変軸へのアクセス)を提供します。選択はタスクによって異なります。
| 特性 | UIFont | CTFont |
|---|---|---|
| フレームワーク | UIKit | Core Text |
| 作成 | systemFont / preferredFont / initWithName | CTFontCreateWithName / CTFontCreateWithDescriptor |
| グリフアクセス | なし | CTFontGetGlyphsForCharacters |
| OpenType機能 | 制限あり(UIFontDescriptor) | フルアクセス |
| 可変フォント | UIFontDescriptor経由 | CTFontCopyVariation / CreateCopyWithVariation |
| レンダリング | UIコンポーネントで自動 | Core Graphics、カスタム |
iOS開発タスクの95%ではUIFontで十分です。Core TextとCTFontは、テキストエディター、PDFジェネレーター、組版レイアウトの書籍、まれな言語のカスタムレンダリングを行うアプリを作成する場合に正当化されます。
iOSでフォントを扱うにはパフォーマンスを考慮する必要があります。各固有フォントは最初のアクセス時にメモリにロードされ、リソースを消費します。San Franciscoシステムフォントはプリロードされており、オーバーヘッドは発生しません。カスタムフォントはファイルからロードされ、最初のロード後にシステムによってキャッシュされます。
アプリ内の固有フォント数は3〜5ファミリーに制限することをお勧めします。各フォントはメモリ内で50KB〜2MBを占有します。同じファミリーの異なるウェイト(regular、bold、medium)を使用する方が、複数の異なるファミリーをロードするよりも効率的です。
システムは作成されたUIFontインスタンスをキャッシュするため、UIFont.systemFont(ofSize: 16, weight: .regular)を繰り返し呼び出しても新しいオブジェクトは作成されません。ただし、カスタムフォントのUIFont(name:size:)は常にキャッシュされるとは限りません。頻繁に使用するフォントは静的プロパティまたはNSCacheに保存し、ファイルからの再読み込みを避けることをお勧めします。
CTFontManagerRegisterGraphicsFontを介してフォントを動的に登録する場合、フォントファイルがネットワークからダウンロードされる場合は非同期になる可能性があります。この場合、UILabelまたはUITextViewは読み込みが完了するまでフォールバックのシステムフォントを表示する必要があります。登録後、フォントが利用可能になり、画面は自動的にテキスト表示を更新します。
よくある質問
はい、UIFontとCTFontはToll-Free Bridgingをサポートしています。変換は単純なキャスト(UIFont as CTFontまたはCTFont as UIFont)で行われます。オーバーヘッドやデータコピーは発生せず、両方のクラスはメモリ内の同じフォントオブジェクトを指します。
すべてのUIコンポーネントにはUIFontを使用してください。UIKitに最適化されており、Dynamic Typeをサポートし、システム設定の変更時に正しく拡大縮小されます。CTFontは、Core Graphicsを介したカスタムレンダリングや低レベルのフォントメトリクスへのアクセスが必要な場合にのみ正当化されます。
ファミリーの一覧にはUIFont.familyNamesを、PostScript名にはUIFont.fontNames(forFamilyName:)を使用します。デバッグモードでこのコードを呼び出し、目的のフォントを見つけてください。PostScript名には通常、ファミリー名とスタイルが含まれます:“SFProText-Regular”、“HelveticaNeue-Bold”。
はい、UIFontDescriptorを介して可変軸(weight、width、slant)を設定できます。ただし、可変フォントのUIFont APIはCTFontCopyVariationと比較して制限されています。可変軸を完全に制御するには、Core TextとCTFontCreateCopyWithVariationを使用してください。
名前とサイズの組み合わせをキーとする静的辞書またはNSCacheを作成します。システムフォントの場合、iOSはインスタンスを自動的にキャッシュしますが、UIFont(name:size:)で作成されたカスタムフォントの場合は、TTFファイルからの再読み込みを避けるためにアプリのキャッシュにオブジェクトを保存することをお勧めします。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。